Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.
A wall thermostat that measures the air inside its own plastic, or a radiator valve that measures the air on the hot metal, will hold the wrong number for the room. Versatile Thermostat is a virtual climate entity. You give it a room sensor and one piece of equipment — a plug on a heater, a climate entity you already have, or a valve — and it decides when that equipment should run. Presets, an open window, someone in the room, and a whole-home power cap are features of that entity, so you do not need a separate automation for each of them.
The regulation method is TPI: each cycle has a fixed length, and the fraction of the cycle spent on grows with how far the room is from the target. Auto-TPI can learn those coefficients from the room instead of making you guess them.
Entity ids are chosen in the integration’s config flow. Do not publish a live thermostat name.
This page is the regulation brain. The pieces around it stay in their own packs:
- A room sensor you still need to build is the ESP32-C6 climate sensor. A second sensor in the same room can sit in front of this one through sensor failover, so a reboot does not look like a failed temperature.
- Window-open climate pause snapshots and restores a climate entity that is not this integration. When Versatile Thermostat is the climate entity, use its own window feature so two automations are not both turning the heat off.
- Sonoff TRVZB external temperature writes a room number into a Sonoff valve and lets the valve decide. An
over_valveentry here decides the opening itself. One of those owns the valve. - HVAC health monitor watches equipment this integration does not control. The integration has its own heating-failure check for the equipment it does control. Run one failure check per heater.
- Adaptive comfort setpoint moves a target from outdoor temperature. Presets here are the targets you choose. Use one writer for the setpoint.
What problem it solves
You want one climate entity per room, driven by a sensor in that room, that cycles a dumb heater or trims a valve, pauses for an open window, and sheds load when the house is near its power cap.
How it works
- Pick the type —
over_switchcycles a plug or relay with TPI.over_climatesits on a climate entity you already have and, in heat or cool, regulates what that entity is asked to hold. Outside heat and cool it sends the underlying device the setpoint with regulation left off.over_valvecommands a valve opening. Sleep on a valve shows the virtual entity as off and requests a full open without asking a central boiler for heat. The valve’s own min and max opening still apply. - Room sensor — the temperature entity is the regulation input. A smoothed curve (an exponential moving average) is what the slope is calculated from, so a single noisy sample does not slam the heater on. Humidity can be attached too, from the same device or a separate sensor, and is exposed as
current_humidity. - Presets — comfort, eco, boost, and frost are temperatures you set. Presence and motion can select a different preset while the room is in use. A manual change on the card can return to the previous preset after a duration you set. If a timed preset was already running, that timer keeps its original end.
- Window — a door or window contact, or a sharp drop in room temperature, pauses heating. The contact is the predictable one. Temperature detection is a fallback for a room with no contact, and it needs tuning so a door that was open for a minute does not get confused with a real cooldown.
- Power — turned on in the central configuration, with two sensors: whole-home power, and a maximum you are willing to hit (an
input_numberworks, so a schedule can lower it). Each virtual thermostat declares the power of the equipment it controls, in W or kW. If turning one on would pass the maximum, it waits. If the house is already over, the central logic sheds virtual thermostats that are closest to their setpoint first, and brings back the ones that were furthest away when there is room again. Shedding uses a hidden preset namedpower. The integration documents a delay of up to about 20 seconds after a new power reading, and it says this is consumption management with a margin, not an electrical safety limit. Keep the maximum under the real breaker or service limit. - Safety — if the room sensor stays unavailable, the integration can enter a security preset instead of regulating on a missing number. That is why the failover wrapper, if you use one, should only substitute a same-room spare, and why its default value should stay blank.
Install the custom integration with HACS, restart Home Assistant, and add it from Settings → Devices & services. The config flow asks for the type, the room sensor, the equipment, and which features (window, presence, motion, power) this room uses. Power sensors are central: every virtual thermostat shares them. Per-room settings cover the sensor, the equipment, the presets, and the declared watts.
Hardware notes
- Room sensor. Any temperature
sensor. An ESP32-C6 Super Mini with an AHT20 or a DHT22 is the build in the climate-sensor pack. Put it in the occupied air, away from the heater outlet and the window draft. - Heater plug.
over_switchneeds a switch rated for the heater nameplate. The linked plug is 15 A. A small electric heater can sit under that. A hard-wired baseboard or a 240 V circuit does not go on this plug. Read the plate, and leave headroom for continuous duty. - Window. Any door or window binary sensor. The linked Zigbee contact is a four-pack. One contact per opening you want to pause.
- Power sensor. Load shedding needs a sensor of whole-home watts, from a meter you already have. There is nothing to buy in this pack for that sensor. An
input_numberin watts is the maximum.
Snippet
The integration is a config flow. The helper below is the maximum the central power feature reads. The cap is yours to set, under the service limit, with margin.
input_number:
heater_power_limit:
name: Heater power limit
min: 0
max: 15000
step: 100
unit_of_measurement: W
mode: box
icon: mdi:flash
In the central configuration, select that helper as the maximum-power sensor and your whole-home power sensor as consumption. On each virtual thermostat, set device power to the heater’s real watts. A thermostat that switches two heaters declares the sum.
TPI cycle length and the on-fraction are configured on the thermostat. A slow hydronic valve wants a longer cycle than a plug-in heater. Auto-TPI replaces a hand-tuned coefficient once the room has run long enough for it to learn. Leave auto-learn off until the sensor, the preset temperatures, and the cycle length are stable, or it will learn your setup mistakes.
Setup outline
- Install the integration. Decide the type from the equipment you have: plug, existing climate, or valve.
- Create one virtual thermostat. Bind the room sensor and the equipment. Enter comfort, eco, and frost. Leave power, window, and presence off until the room holds temperature on its own.
- Watch a cycle. The equipment should run a fraction of the cycle when the room is near the target, and a larger fraction when it is far below. If it short-cycles, lengthen the cycle.
- Add the window contact. Open it, wait out the detection delay, and confirm the virtual thermostat stops calling for heat. Close it and confirm the preset returns.
- Turn on central power only after the whole-home sensor and the
input_numberboth read in watts (or both in kW — the integration normalizes). Set each device’s declared power. Confirm a test over the maximum sheds a thermostat and that it returns when the load drops.
Troubleshooting
- The room oscillates. The cycle is shorter than the room can respond, or the room sensor is in the heater’s airstream. Lengthen the cycle and move the sensor.
- The underlying thermostat fights this one.
over_climateand a second automation are both writing the setpoint. The window-open pack, the adaptive-comfort pack, and this integration should not all command the same entity. Leave this integration as the writer. - A valve barely moves, and the room sensor is ignored. The valve is still using its internal probe. That is the external-temperature pack’s job, or switch the valve to
over_valveand stop writing the external number from somewhere else. - Load shedding never releases. The maximum is below the house’s idle load, the power sensor is in kW while the max helper is in W and the units were not set to match, or declared device power is larger than the heater. The integration’s unit setting accepts W, kW, or auto.
- Heat stays on with the window open. The contact entity is inverted (
onmeans closed on some sensors) or the feature was left off for this thermostat. Check the binary in Developer Tools with the sash open. - Security preset after every reboot. The room sensor is
unavailableduring the node’s boot, and the timeout is shorter than that boot. Lengthen the timeout, or put a same-room spare behind sensor failover.
Credits
Based on Versatile Thermostat by jmcollin78 (a rewrite of the earlier Awesome Thermostat). Window, power, TPI, and valve behavior follow that project’s documentation: power management, window detection, and algorithms. This write-up is an original setup overview for a room sensor, a heater plug or valve, and a power cap. It is not a copy of the integration.