Perfect Heating Automation with Sonoff TRVZB

Hi

I used this TRV the entire last winter via ZHA with the default HA thermostat, its built-in temperature sensor, default “accuracy” (hysteresis) of 1 degree C and manually adjusted compensation (0.2C) and I was satisfied with it.

But we always want more and better, don’t we? :slight_smile:

In preparation for the upcoming winter (it’s already cold here) I upgraded it today to firmware version 1.3.0.

I was able to set it to use an external sensor and by using Tom’s (photomoose’s) template it correctly syncs with the external temp sensor (thanks a lot for that!). I also adjusted its “accuracy” (hysteresis) to 0.2 degrees C.

Now I’m trying to figure out how to use the percentages for the valve open and close positions. I can’t find any entity at all mentioning “valve” and I checked and rechecked all the entities associated with the Sonoff TRVZB and none of them mentions a % for the valve open/close positions. Could you please share a hint here on how to identify and use them?

Also related to this, I haven’t yet used any of the “Better Thermostat”, “Versatile Thermostat”, “Smart Thermostat PID” and so on. Could anybody please share which one(s) would be the better choice to use the % open/close of the Sonoff TRVZB?

Thanks a lot!

LE: I gave AI a spin to compare “Better Thermostat”, “Versatile Thermostat”, “Smart Thermostat PID” and frankly I’m a bit taken aback by how helpful it was :slight_smile: It even recommended me an option (Versatile Thermostat) based on a number of questions so I’m going to check it out. Computers making choices for humans, what have we done? :slight_smile:

LLE: So it seems that I first need to sort out the question about how to find & use the valve open/close % setting for the TRVZB:

" How to Choose the Type Choosing the correct type is crucial. It cannot be changed later via the configuration interface. To make the right choice, consider the following questions:

  1. What type of equipment will I control? Follow this order of preference:
    If you have a controllable thermostatic valve (TRV) in Home Assistant through a number entity (e.g., a Shelly TRV), choose the over_valve type. This is the most direct type and ensures the best regulation."
    versatile_thermostat/documentation/en/creation.md at main · jmcollin78/versatile_thermostat · GitHub

Solved by upgrading HA core from 2025.7.1 to 2025.9.3

Dear Dan @dannutu ,

I am new in HA. İ installed trvbz and snzb02 temp sensor in z2m . When I check settings I see 3 external sensors in trvzb z2m menu. I did not understand how to link this field to one of my sensors as I not see my sensors names in Dropbox
Menu.

What I do is wrong? I should use ewlink? Please help

Regards

same here… during time the setting switches through the externals. What this means, I dont know…
I set the external temperature like described with an automation that is triggered by an external temperature sensor and updates the external entity of the device (number.XY_external_temperature_input)
That seems to work, but what’s causing the change of the 3 externals in Z2M, I cannot recapitulate.

Hello,

i changed my heating setup from MAX Thermostats and FHEM to Sonoff TRVZBs with Z2M. Already in FHEM i completely overwrited the MAX-internal control of the valve and implemented a PID.

And it looks like that also with the sonoff valves i need to control it in a better way. Of course better thermostat is not bad but with the external temperature sensor-function of the sonoff valves BT is not really need. The only good thing about it is the better dashboard widget instead of the default HA climate-widget.

The main problem still is that it looks like that the values always fully open or close instead of regulating the valve position based on some smart parameters. Even my analog valve do a better job in this part. The only thing of the analog ones are i can’t remote control them and give them schedules.

So I thing i look like a good plan to remove BT again from the chain and adding some smart PID-regulator instead.

For the whole discussion i want to add for everyone that i use “scheduler card” and “scheduler component” from HACS to nicely set heating plans for my rooms.

1 Like

Depending on heating system, i guess, but in my case it doesn’t matter if valve is “just a tiny bit opened” or “full opened” - in both cases i have equally warm-hot radiator. The water pump which pushes hot water causes this. I tried once without pump (only gravity fed warm water circulating) and the temperature of radiators was different regarding how much valve is opened, but in my case gravity system is not usable since not all my radiators are warm in that case, so pump is a must.

My system is (as i’ve wrote elsewhere) only with sonoff valve and xiaomi BLE thermometer (LYWSD03MMC), no BT or versatile thermostat addons. HA automation sends Xiaomi temp.value into sonoff external temperature sensor and that’s it. (of course, i have enabled external temperature sensor in sonoff). So i only use sonoffs as “on/off switch”, which is quite ok - i have room temperature ± 0,5 degree (celsius) while set sonoff’s hysteresis to 0.4 degree.

Regarding sonoff’s original external temperature sensor: i’ve read that they are not precise and they tend to fluctuate up/down a lot, so i guess it’s better to use some other sensors. For example Xiaomi BLE thermo/hygro sensors are certainly cheaper, and according to my experiences very precise.

Really interesting post. Which zigbee hub do you have? I have a moes gateway hub and it can’t pair with the sonoff trv

I have Sonoff Zigbee 3.0 USB Dongle Plus V2 and additionaly Sonoff zigbee zbmini r2 as proxy, they both work. I’m thinking however to buy ethernet hub / router, but still figuring out which one. Not all models work in HA, as i read…

Thanks. What’s the need for the proxy/router zigbee? I assume it’s for areas where there is not enough signal, but wanted to make sure

I thought zigbee range was wide enough to cover a house, I think I did read 80meters, so I assume if WiFi signal reaches a point in the house, zigbee will do it too (considering the zigbee dongle is near the router)

Well… “covering the house” is relative… my house is old, made from bricks, wooden ceilngs… so i’m good, but my friend lives in apartments block with reinforced concrete walls and even wifi doesn’t reach from living room via hallway to his bedroom, let alone zigbee… i guess it’s best to try and see. You can observe signal strength over time, if it’s ok then you don’t have to worry.
I only have 3 sonoff trvzb valves on zigbee, all other modules are wifi, so for now it’s not a problem. From what i’ve read there’s also a limitation of number of zigbee devices one router can handle.
For extending coverage you have more options, like zigbee-to-wifi extender, zigbee-to-ethernet, then many end devices can be proxies - like mentioned sonoff zbminir2, it’s just that it needs to be installed in a place with still decent signal, then it passes other devices on to main device.
But i’m still a noob in zigbee world, so i’m also still learning…

1 Like

You might be confusing it with marketing bullshit something else. Zigbee signals will reach maybe 1/10 of that in open air, depending on whether your coordinator has a beefy external antenna or not.
Something with this tiny antenna can’t be expected to realistically reach 80m. Look at it this way - if your WiFi router had an antenna that tiny, would you believe you’d get a signal 80m away?

Ok, so realistically how wide is the range? Would it cover the first floor of my house or not even that?

Depending on your house construction (brick/plasterboard/concrete) a single coordinator might struggle. General advice is to put at least one zigbee router in each room.

Then again, I got lucky. These are my zigbee networks with 18cm brick walls highlighted in yellow and concrete floors highlighted in red. You’ll notice I still have direct connections to the coordinator (solid lines), even for the farthest routers on Z2M. ZHA does slightly worse, but read the notes below, plus some of my routers are offline because I’m replacing them.

Z2M with Tube’s ZB coordinator with Ethernet & external antenna (antenna replaced with a larger one from an old android box):

ZHA network with the original Sonoff Bridge (tiny antenna and uses only Wifi to communicate with my network):

Thank you all for your instruction and help. It really helped me use an external sensor.

What I don’t understand is why the system changes from external to external_2 and external_3 and suddenly starts heating. I just have one temp sensor. What are the other external anyway?

i have a question about the scheduler. My understanding is that, once the room temperature meets a condition, it sets the temperature for the valve, but… then, how is this linked to the boiler controller itself? It is, you need to open the trv, but you also need to send a signal to the hvac module to start heating isnt it? Where are you doing this?

Short answer: I don’t think it does. You may have many TRVs, so you need to have a separate control loop that monitors the state of each TRV and enables the boiler if any of them are calling for heat.
I did it by having a “living room needs heat” input_boolean for each room and then have the boiler come on if any was true.

Great topic and great thread.
I have basically done all of these things as well and have to say that the TRVZB is a great thermostat. There was one thing I have been missing, so I built an API for that. Before jumping into that let me just explain the use case:
I moved from a newly built apartment with floor heating and central heating control, and now to a 120 year old apartment with 6 wall mounted radiators. So clearly I needed the thermostats!
At first I just went with the vanilla setup that the thermostats provide over MQTT. But I was missing the supervisory control that would allow me to simply set a mode for the entire apartment - like stay_home to keep it nice and warm during the day - so basically control and manage schedules in one place.
So that where this API comes in - it is built in python and fastapi. I have integrated the API with HA to be able to set the modes directly from HA - ei. I have a dropdown that allows me to set the mode for all thermostats.
Ideally this API should be implemented in HA (like an integration) - that might be my next move.

feel free to have a look at the API here - If there is anything I can do to help, feel free to ask

1 Like

Preface
This topic and using TRVZB with HA have taken quite a turn after Sonoff released firmware for setting up the temperature hysteresis.
I’ve had my TRVZB’s only for a while and I was happyt to start with Firmware 1.4.1.
I quickly disregarded all Better Thermostat or Versatile Thermostat as I felt that they gave me nothing that could not be done with few lines of automation now that TRVZB’s support setting the external temperature sensor “natively” (May not work with ZHA, but works like a charm* (more on that later) with Z2M

Preface vol2
I ended up with a setup where I have one temperature sensor (SNZB-02P) for each room and plain simple automation to trigger on every temperature update and just to be safe once every hour to update the temperature to each correspondin TRV’s external temperature.
Then set the hysteresis to -0.2C and set temp sensor to external and go on live with your life. Life is good for the next 24 to 48 hours untill your home temperature eventually stabilize and then go crazy… what? go Crazy you say? Why?

Bugs
Well there be bugs. Lot of them.
There is very thinly documented feature about the external temperature sensors.
You may have noticed that z2m has four settings for that.

internal is internal
external is external
external_2 is when the TRV have not received temp updates* for 2 hours and reverts back to internal
exgternal_3 is when TRV received temp update* from external when being flagged as external_2

But why? I don’t know.
I monitored my TRV’s and noticed that they went from internal to external_3 (through external_2) in no-time. Sigh. And bug #1. When TRVZB is in external_2 state it still happily reports it’s own externally stored temperature as what was the last temperature. So unless you monitor what’s the string on external temperature source you’ll never knew what’s going on. Last temp was 20.0C it will show that everywhere even though it’s blatantly obvious that the TRV is internally following some other temperature source and behold you can see external_2 in the temperature source.

And why is this? You may recall I said that I’m running my automation once an hour just in case. And 1 < 2… well the bug #2. Or feature_hidden? When setting up the temperature, should the temperature be exactly the same float … it does not update all the way to the TRV. The temperature must change or in 2 hours the TRV will fallback to internal sensor even though the reason for that was that the temperature was stable (AS IT SHOULD BE :D)

Heureka?
Claim above can be tested by setting the number to any arbitrary number, say 21.2 C
hall_trv Temperature changed to 21.1 triggered by automation
then set it again immediately after and observe the logs…
(no line here haha)
Then set it to 21.11 (see the added one hundredth of a degree
hall_trv Temperature changed to 21.11 triggered by automation and immediately after
hall_trv Temperature changed to 21.1 triggered by automation
interesting. How about 21.12?
hall_trv Temperature changed to 21.12 triggered by automation and immediately after
hall_trv Temperature changed to 21.1 triggered by automation
Okay 21.19, this must round up right?
hall_trv Temperature changed to 21.19 triggered by automation and immediately after
hall_trv Temperature changed to 21.1 triggered by automation
Heureka!

Solution (hack)
My solution to all of this was to introduce Jitter
Specifically every time sensor get’s update it will just update it’s new temp to TRV (which is relatively rarely) but when the automation is triggered by time it will jitter the temperature between +0.01 to +0.09
So 21.1 will became 21.11 - 21.19 which in turn will be interpreted as 21.1 and no accuracy will be lost but the TRV will see that the external sensor is alive. (and after I wrote this I remembered that I’m jittering everything, well maybe that’s for the best)

This also means that I can keep the battery temperature sensors as battery efficient as possible. Currently running them with default settings (minimum temp delta to report 0.1C and maximum time between reports 3600 seconds (1 hour)) the maximum time between reports does not matter at all as if the sensor reports every hour that “temp is now 21.1 C” then TRV will completely lose its mind after 2 hours “no updates bro! must go internal”

Sigh. I’m sick of tired of fixing bugs with my own bugs :smiley: Have fun. I may share the automation should anyone need it. Narf, I’ll just share it here right now - parts of it atleast.

Automation example (BAD EXAMPLE, READ CONCLUSION AND TL;DR BELOW
Triggers (all rooms in one automation heck yeah!)

triggers:
  - entity_id: sensor.kitchen_sonoff_temperature
    id: kitchen
    trigger: state
  - entity_id: sensor.hall_sonoff_temperature
    id: hall
    trigger: state
  - entity_id: sensor.kidsroom_sonoff_temperature
    id: kids
    trigger: state
  - entity_id: sensor.bedroom_sonoff_temperature
    id: bedroom
    trigger: state
  - id: refresh
    trigger: time_pattern
    hours: /1

Actions

  - choose:
      - conditions: # n amount of these, one for each room
          - condition: template
            value_template: |
              {{ trigger.id == 'kitchen'
                 and is_number(trigger.to_state.state) }}
        sequence:
          - target:
              entity_id: number.kitchen_trv_external_temperature_input
            data:
              value: >
                {% set t = states('sensor.kitchen_sonoff_temperature') | float
                %}  {% set jitter = (range(1, 10) | random) / 100 %}  {{ (t +
                jitter) | round(2) }}
            action: number.set_value
      - conditions: # one of these, just for the time pattern
          - condition: template
            value_template: "{{ trigger.id == 'refresh' }}"
        sequence:
          - if: # n amount of these, one for each room
              - condition: template
                value_template: >-
                  {{ is_number(states('sensor.kitchen_sonoff_temperature')) }}
            then:
              - target:
                  entity_id: number.kitchen_trv_external_temperature_input
                data:
                  value: >
                    {% set t = states('sensor.kitchen_sonoff_temperature') |
                    float %}  {% set jitter = (range(1, 10) | random) / 100
                    %}  {{ (t + jitter) | round(2) }}
                action: number.set_value

Conclusion
This is now as close to perfect TRV operation as it possibly can be without PID and with full zero to 100% close -to- open cycles.
Works for huge residential central heating, may not work if you have one house boiler that needs to ramp up - or maybe it will. Who am I to judge - I’m just a guy who spent 100 hours fixing analog and adeguate wax thermostats with hundreds of lines of code - testing and some booze.
Shii… I just realized that I may not have to Jitter the temp. The whatever extra decimal used is not stored anywhere. I could possibly get away recycling numbers. It can be two every time? heck Testing this right now. And verified. No need to Jitter, just add 0.01 C to every temperature and that’s enough to fool TRVZB or Z2M - at this point I’m too tired to check who’s to blame.

TL;DR; (dont Jitter as I did, read atleast previous chapter and this TL;DR)

  1. You’ll need to add fake numbers to the external temperature sensor’s temp. Othervice you’ll end up TRVZB (atleast with FW 1.4.1) reverting to internal sensor after 2 hours of stable temperature. E.g. add 0.01C every report and TRV or Z2M or something will see “oh what a nice new number, definitely not the previous number I’ve stored”
  2. And while the sensor goes silently to external_2 it will still show eveywhere in the data that it would follo whatever was the last external temp (it’s lying)
  3. Setting up the temperature with higher resolution than 0.1C there is undocumented floor function that will clip the last decimal and happily force push onward whatever is left of the temp. i.e. 25.99 C will be reported and stored as 25.9 C not 26.0 C
1 Like

Yeah, well… YOU know that, but try doesn’t. If no temperature change is reported it COULD be because it’s stable, but then again it could also be because external sensor is unavailable. TRV can’t know that, thus 2-hour mandatory report - just to see that sensor is "alive and kickin’ ".

I have time interval for reporting temperature set to 15 minutes. 1 hour is theoretically enough, but in practice if it happens that report by accident info doesn’t reach trv it will perhaps switch to internal, since next try is after 1 hour (depends on clock accuracy which event comes first).
Although temperature can stabilize i find pretty hard to believe that in 2 hours it doesn’t change even for 0.1 degree… :thinking: Perhaps temp.sensor is set to 0.5 degree accuracy?

And, it works quite well in ZHA. Only - ZHA doesn’t have internal_2 and internal_3 sensors, so i can’t see their state. In fact, i like this approach, since if you develop automation it’s good thing to know details, if it’s working ok, but as said, sadly zha doesn’t know that info…

All my temp sensors are reporting in 0.1 C increments. Their treshold to report new temperature is delta 0.1 C. It’s entirely possible that the sensors have some smoothing in them to prevent them going overboard on small adjustments. But nevertheless the temperature seems to stay that stable. Less than 0.1C changes within an hour. This building has relatively good insulation and huge thermal mass compared to size.
I’m also aware that cheap sensors usually are not that accurate but I can verify these with my IR thermometer and by measuring things that have comparable emissivity I’ve verified that the temperature difference between rooms correlate exactly (or within sensor accuracy) between these measurement systems. That’s why I’m not that keen on believing that the sensor accuracy would be anything else than 0.1C as it would have to so-cleverly extrapolate the extra resolution which is harder to accomplish without getting caught by a paranoiac geek with too much tools.

It would not matter if in my case I would force update every 5 minutes if the temperature have not changed. Currently the 1 hour forced update from the temp sensor is no-good as it proves nothing else than “last seen” data which is also not applicable in this scenario.

It’s possible that TRVZB can’t know if the sensor update is from bad source or not. But that should be left to the user to know or to implement in upstream. I can know if the sensor data is reliable. I can see if the battery is not empty and sensor is reporting in every hour regardless of the lack of variance in the temperature. TRV should care only if there are updates. Lack of updates for x hours → revert to internal.