# Analytics snippet placeholder — HearthNodes (gatherer.top) # Paste the measurement snippet here (server.js inlines any content that contains # a markup tag into on every page). No GA4 property is assigned to this # site yet, so leave this file as comments only and the build emits no tracking # code.
HearthNodesgatherer.top live 27/28 EN 中文

Radiator-by-radiator balancing from room temperature curves

Thermostatic valves on seven radiators learn each room's heating curve over two weeks, then trim the valve position to hold ±0.4 °C instead of ±1.6 °C, which cut gas use by 12 % in a leaky 1970s flat.

protocol · zwave latency · 1200000 ms power · battery published · 2026-10-14 3 devices
Automation YAML climate-radiator-balancing.yaml
# HearthNodes recipe 14 - radiator balancing from room curves
alias: "Climate - per room radiator balancing"
id: hn_climate_radiator_balance
description: "Learned per-room offsets hold +/-0.4 C instead of +/-1.6 C"
mode: queued
max_exceeded: 4

trigger:
  - platform: state
    entity_id: binary_sensor.heating_season_active
    to: "on"
  - platform: time
    at: "02:30:00"
    id: nightly_refit
  - platform: template
    value_template: >-
      {{ (states('sensor.living_temperature') | float(20)
          - states('input_number.living_target') | float(20)) | abs > 0.8 }}
    for: "00:20:00"
    id: deviation

variables:
  rooms:
    living:    { sensor: sensor.living_temperature,    valve: climate.radiator_valve_living }
    study:     { sensor: sensor.study_temperature,     valve: climate.radiator_valve_study }
    main_bed:  { sensor: sensor.main_bed_temperature,  valve: climate.radiator_valve_main_bed }
    second_bed: { sensor: sensor.second_bed_temperature, valve: climate.radiator_valve_second_bed }
    bath:      { sensor: sensor.bath_temperature,      valve: climate.radiator_valve_bath }
    hall:      { sensor: sensor.hall_temperature,      valve: climate.radiator_valve_hall }
    kitchen:   { sensor: sensor.kitchen_temperature,   valve: climate.radiator_valve_kitchen }

condition:
  - condition: numeric_state
    entity_id: sensor.outdoor_temperature
    below: 15
  - condition: numeric_state
    entity_id: sensor.boiler_flow_temperature
    above: 45

action:
  - choose:
      - conditions:
          - condition: trigger
            id: nightly_refit
        sequence:
          - service: script.learn_heating_curve
            data:
              rooms: "{{ rooms }}"
              min_r2: 0.6
      - conditions: []
        sequence:
          - repeat:
              for_each: "{{ rooms | dict2items }}"
              sequence:
                - service: climate.set_temperature
                  target:
                    entity_id: "{{ repeat.value.valve }}"
                  data:
                    temperature: >-
                      {{ [[states('input_number.' ~ repeat.key ~ '_target') | float(20)
                           + states('input_number.' ~ repeat.key ~ '_offset') | float(0),
                           5] | max, 30] | min }}

# Offsets are clamped to +/-2 C and are only enabled after a two week learning
# run. More than two heads offline -> balancing stops and every valve goes to the
# plain schedule target, with the notification saying so. Hydraulic faults are
# fixed at the lockshield valve, never in software.
Trigger · state

binary_sensor.heating_season_active

A room's temperature deviates from its schedule target by more than 0.8 °C for 20 minutes.

Radiator-by-radiator balancing from room temperature curves topology

Step-by-step

  1. climate.radiator_valve_[room]Apply a per-room offset learned from the curve model, clamped to ±2 °C, so a slow room gets a higher valve target than a fast one. set_temperature · {{ target + offset }}
  2. script.learn_heating_curveRefit each room's first-order response curve nightly using the day's valve position and temperature data, and reject the fit if R² is below 0.6. nightly · 02:30 · update coefficients
  3. climate.boiler_flowSet the boiler's flow temperature from the outdoor temperature curve, which is what makes the valves' job possible at all. set_flow_temp · weather compensated
  4. counter.balance_cycleProduce a weekly report of per-room deviation so a radiator that is genuinely undersized shows up as a persistent negative bias. increment · weekly report
Step-by-step
Put the temperature sensor where people are, not on the radiator

A valve head's built-in sensor reads the pipe, not the room. Mount a separate sensor on an interior wall at 1.2 m, away from direct sun and at least 50 cm from any heat source. This single change typically removes 70 % of the complaint that 'the thermostat is wrong'.

Learn for two weeks before you trust it

The first-order curve needs at least ten heating cycles per room to be meaningful. Run the system on the plain schedule for two weeks with logging on and only then enable offsets. Enabling offsets on day one produces oscillation that looks like a hardware fault.

Do not balance a system that is not balanced hydraulically

If one radiator is always cold at the bottom or noisy, the problem is the lockshield valve, not the smart head. Set the lockshield valves by the temperature-drop method first: 10–12 °C drop across each radiator. Software cannot fix a hydraulic fault.

Hardware

ModelProtocolLinkRole in this chain
Z-Wave thermostatic radiator valve heads (e.g. Danfoss Ally or Eurotronic Spirit) zwave wireless Seven heads, one per radiator. Z-Wave is used because it reports the valve's actual opening percentage, which the learning script needs.
Room temperature sensors, one per room, 1.2 m height zwave wireless Separate from the valve heads — a valve head's own sensor sits 10 cm from a hot pipe and reads 3 °C high.
Outdoor temperature sensor on a north wall zwave wireless The weather-compensation input; a sensor in sunlight will disable the boiler in winter.

When it fails

If a valve head loses communication, it reverts to its own local schedule, which is a reasonable default. If more than two heads are offline, the automation stops balancing and sets all valves to the schedule target without offsets, and the notification says so — degrading to a dumb system is better than balancing against missing data.

Recipes on the same trigger source

Terms Informational only. These recipes control mains electricity, water and physical access. You are responsible for local electrical and plumbing codes, for fusing and isolation, and for testing every fail-safe yourself. Nothing here is professional engineering, legal or safety advice.