Blog › Open by choice

Node-RED for heating: a flow to manage your zones

Home Assistant shows the rooms and collects the data. The logic that decides when to open a zone is better kept in Node-RED, where you can see it, test it and copy it from one zone to the next. Here is a complete flow, node by node.

January 21, 20266-minute readLeggi in italiano

In a Brick system, two open-source tools work together. Home Assistant is the interface: it shows the rooms, collects device data and provides the app. Node-RED is where the logic lives: it decides when a zone should heat, how it coordinates with the others and what to do if something goes wrong.

Using Node-RED for heating control alongside Home Assistant is not compulsory, since Home Assistant has its own automations. For heating control, though, it pays off, and in this article we look at why and how, by building the flow for one zone.

Diagram of a Node-RED flow with sensor, schedule, mode, active set point, hysteresis, actuator, Grafana and alert nodes
The flow for one zone: the sensor, the schedule and the mode set the active set point; hysteresis drives the actuator, sends data to Grafana and raises an alert if the zone does not reach temperature.

Why Node-RED alongside Home Assistant

Node-RED is a visual programming environment that started at IBM and is now run by the OpenJS Foundation. You build logic by wiring nodes together: one node reads a value, another processes it, another sends a command.

For anyone controlling heating systems it has three advantages over automations written in Home Assistant.

  • You can see the logic. A zone’s flow is a drawing you read from left to right. A colleague, or you in two years’ time, can understand what it does without reading hundreds of lines.
  • You can test one piece at a time. Inject a fake temperature, watch what comes out of each node, fix it.
  • You can copy it. Once zone 1 works, the other seven are copies with a different name.

Anyone with a background in professional building management will find a familiar way of working: function blocks wired together.

The flow, node by node

A zone’s flow has three inputs, a core and three outputs.

Inputs.

  1. The zone sensor. A node listening for state changes on the Home Assistant entity that represents the sensor, for example sensor.bedroom_temperature. Every new reading enters the flow.
  2. The schedule. A node that switches the zone’s time band at set times: comfort from 6 to 9 am and from 6 to 11 pm, set-back for the rest of the day.
  3. The mode. A selector the client changes from the app: Comfort, Eco or Auto. In Auto the schedule applies; in the other two the set point is fixed.

Core.

  1. The active set point. A node that combines schedule and mode and decides the current target temperature, for example 20.5 °C in comfort and 18 °C in set-back. The value is stored in the flow context, where the other nodes read it.
  2. Hysteresis. The node that decides whether the zone should heat. It switches on when the temperature drops below the set point minus 0.3 °C, and off when it rises above the set point plus 0.3 °C. In between it keeps the previous state, so the actuator does not keep opening and closing.

Outputs.

  1. The actuator. A node that calls the Home Assistant service to switch the zone output on or off.
  2. Grafana. Temperature, set point and actuator state go into the database, for charts and to understand how the zone behaves over time.
  3. The alert. If the zone has been calling for heat for three hours and still has not reached temperature, a notification goes out. It usually means a stuck actuator, a loop closed at the manifold or a heat source that is not responding.

The heart of it: hysteresis in a function node

You can build hysteresis from ready-made nodes, but a function node of a few lines is clearer:

// Input: msg.payload = zone temperature in °C
const sp = flow.get("setpoint_zone1") ?? 20;
const hyst = 0.3;
let state = context.get("state") ?? false;
const t = Number(msg.payload);
if (isNaN(t)) return null;            // invalid reading: change nothing
if (t <= sp - hyst) state = true;     // below threshold: heat
else if (t >= sp + hyst) state = false; // above threshold: stop
context.set("state", state);
msg.payload = state;
return msg;

Two details matter. An invalid reading, for example when a wireless sensor’s battery is flat, must not change the state. And the hysteresis value has to suit the system: 0.3 °C is fine for slow underfloor heating; a faster fan coil may need different values and minimum on-times.

Schedules and modes

The schedule is the part the client sees and changes most often. So the values are best kept in Home Assistant, as entities editable from the app, with Node-RED reading them. The client moves the wake-up time in the app and the flow follows, without anyone opening Node-RED.

A practical tip for underfloor heating: instead of switching the zone on at the comfort time, bring it forward by an amount that depends on the outdoor temperature and on how far the zone is from its set point. You can start with a fixed lead time, say two hours, and refine it by looking at the charts from the first few weeks.

From one zone to the whole system

The zone flow is the building block. The system is built on top of it, with a flow that looks at all the zones together:

  • if at least one zone is calling for heat, the circuit pump starts and a demand goes to the heat source;
  • if no zone is calling, the pump and heat source stop after a delay, to avoid short cycling;
  • the flow temperature follows the heating curve, with a small correction based on how many zones are up to temperature.

This is where Node-RED shows its strength: each level is a separate flow, readable and testable on its own. As we wrote about Home Assistant in a professional installation, the difference from DIY is not the software but the way it is used: documented, tested, repeatable.

The most common mistakes

People starting out with Node-RED for heating control tend to trip over the same things.

  • Logic scattered between Home Assistant and Node-RED. Half the rules in a Home Assistant automation, half in a flow: after a month nobody knows what controls what. Better to have a clear rule: logic in Node-RED, editable values in Home Assistant.
  • No handling of missing data. A wireless sensor that stops transmitting leaves its last reading in place. If that reading was low, the zone heats for ever. Check how old the last reading is and, past a certain time, put the zone into a safe state and send an alert.
  • Ignoring minimum times. Actuators, pumps and heat sources do not like switching on and off every few minutes. A minimum delay between one change of state and the next protects the components.
  • Unnamed flows. Nodes called “function 12” and “switch 3” make a flow unreadable. Each node’s name should say what it does.

Before you put it into service

Before connecting the flow to real actuators, test it with values injected by hand: temperatures below and above the threshold, invalid readings, mode changes. And export the flow and keep it with the system diagram. The flow is part of the documentation, just like the wiring diagram.

Download the flow

The flow described in this article, ready to import into Node-RED. Rename the entities to match your system and test it on one zone first.