Sistema Avançado de Controle de Aquecimento Multizona para Casas Inteligentes
Componentes e Materiais
| Componente | Quantidade |
|---|---|
| Arduino UNO (use Mega se >5 zonas) | 1 |
| Placa Relé 8 Canais 5V Keyes | 1 |
| Atuador Termoelétrico Linear Honeywell MT8-230-NC (230V AC) | 1 |
Sobre o Projeto
Construí este dispositivo porque minha cozinha ficava muito quente ou muito fria com um único termostato na sala. Controladores multizona comerciais (como EvoHome) são muito caros. Este programa captura a inteligência desses sistemas caros, rodando em um simples Arduino Uno. Resolveu totalmente meu problema.
Destaques/Recursos
- Configure apenas pinos e número de zonas.
- Arduino Uno controla até 5 zonas de piso radiante.
- Com Arduino Mega, número de zonas é praticamente ilimitado.
O Programa Controla
- Bomba do piso radiante.
- Agrega todas as zonas como um único termostato para a caldeira central.
- Válvulas para abrir/fechar zonas.
- Watchdog timer para operação sólida.
Aquecimento Individual por Zona
- Por zona: termostato para detectar demanda de aquecimento.
- Por zona: relé para controlar uma ou mais válvulas dos grupos de piso radiante da zona.
- Ambiente com múltiplos grupos de piso radiante = uma zona (ligue válvulas em paralelo ao relé da zona).
- Mais conveniente e economiza energia: ambientes não superaquecem.
Controle da Bomba do Piso Radiante
- Liga bomba apenas quando necessário para aquecimento. Economiza 100-200 €/ano em eletricidade (bomba 80W ligada 24/7 = 2kWh/dia = 0,50 €/dia).
- Ativa bomba ao menos uma vez a cada 36h por 8min se não houve demanda (verão).
- Evita ligar bomba sem abrir válvulas antes (elas levam 3-5 min).
Controle Opcional do Restante da Casa
- Cômodos sem piso radiante geralmente têm válvulas termostáticas nos radiadores; apenas os frios aquecem.
- Adicione termostato nos cômodos desejados. Ligue-os em paralelo à entrada
No_Zone.
Notas Finais
- Nem todas as zonas precisam ser controladas; apenas as que ficam muito quentes ou frias (outras usam botões manuais no coletor).
- Decidi explicitamente não conectar à internet:
- Aumentaria risco de mau funcionamento (precisa ser robusto).
- Termostatos inteligentes já controlam a casa remotamente; este controlador não agrega valor para adaptação remota.
Código
ProjectCV.ino
/* Controlador de Aquecimento Piso Radiante Multi-Zonas v1.0
* Copyright: GPL-3.0 por Eric Kreuwels, 2017
* Créditos: Peter Kreuwels por definir casos de uso
* AVISO: FAST_MODE é para teste/depuração (loop 50x mais rápido).
* Cuidado com FAST_MODE em bomba real: válvulas precisam 3+ min para abrir.
* Em operação normal, loop roda ~10x/seg (10 contagens/seg; 600 ≈ 1 min)
*/
#define VALVE_TIME 3000L // 5 min para abrir/fechar válvula (segurança)
#ifdef FAST_MODE
#define PUMP_MAINTENANCE_TIME 108000L // Teste: manutenção bomba a cada 4 min
#else
#define PUMP_MAINTENANCE_TIME 1300000L // Normal: manutenção a cada 36h
#endif
#define PUMP_ACTIVATION_TIME 5000L // Bomba ligada ~8 min (10s teste)
#define COOLDOWN_TIME 18000L // Pós-aquecimento: circula água 30 min (40s teste)
#include <avr/wdt.h> // Watchdog
#include "./Devices.h"
struct Zone {
String name;
Valve valve;
Thermostat thermostat;
};
//////////////////////////////////////////////////////
// BLOCO DE CONFIGURAÇÃO
// Configure/reordene pinos como preferir (minha fiação no Uno):
#define HEATER_PIN 4 // Relé → entrada termostato da caldeira
#define FU_PUMP_PIN 5 // Relé → Bomba Piso Radiante
#define LIVING_VALVE 7 // Zona 1: Relé → Válvula(s)
#define KITCHEN_VALVE 6 // Zona 2
#define DINING_VALVE 3 // Zona 3
#define LIVING_THERMO 8 // Zona 1: Entrada → Termostato sala
#define KITCHEN_THERMO 9 // Zona 2
#define DINING_THERMO 11 // Zona 3
#define NO_ZONE_THERMO 10 // Opcional: termostatos sem piso radiante
#define HEATING_LED 12 // Aceso: aquecendo; Pisca: cooldown; Apagado: ocioso
#define INDICATION_LED 13 // Pisca indicando placa viva; pode remover para liberar IO
#define NR_ZONES 3
Zone Zones[NR_ZONES] = {
{"Sala", Valve(LIVING_VALVE, "Valvula Sala"), Thermostat(LIVING_THERMO, "Termostato Sala")},
{"Cozinha", Valve(KITCHEN_VALVE, "Valvula Cozinha"), Thermostat(KITCHEN_THERMO, "Termostato Cozinha")},
{"Jantar", Valve(DINING_VALVE, "Valvula Jantar"), Thermostat(DINING_THERMO, "Termostato Jantar")}
};
// FIM CONFIGURAÇÃO
//////////////////////////////////////////////////////
LED iLED(INDICATION_LED, "LED Indicador");
LED hLED(HEATING_LED, "LED Aquecimento");
Manipulator CV(HEATER_PIN, "Caldeira");
Pump FUPump(FU_PUMP_PIN, "Bomba Piso Radiante");
Thermostat ZonelessThermo(NO_ZONE_THERMO, "Termostato Sem Zona");
void printConfiguration() {
Serial.println("------ Configuração da Placa: ---------");
iLED.Print(); hLED.Print(); CV.Print(); FUPump.Print(); ZonelessThermo.Print();
for(int i=0; i 0) cooldownCount--; return checkCoolDownNeeded(); }
bool checkCoolDownNeeded() { return (cooldownCount > 0); }
void Print() {
switch(_State) { case idle: Serial.print("ocioso"); break; case on: Serial.print("ligado"); break; case cooldown: Serial.print("cooldown"); break; }
}
};
State CVState;
void setup() {
Serial.begin(115200);
printTimeStamp(); Serial.print(": ");
#ifdef FAST_MODE
Serial.println("Controlador Zonas CV iniciado em Modo Teste!\n - Tempo roda ~50x mais rápido\n - Ciclo manutenção bomba a cada 3h em vez de 36h");
#else
Serial.println("Controlador Zonas CV iniciado. Timestamps (dd:hh:mm:ss)");
#endif
Serial.println(" - Formato timestamps (dd:hh:mm:ss)");
printConfiguration();
wdt_enable(WDTO_1S); // Watchdog: reset se não "acatar o cão" em 1s
}
void loop() {
#ifdef FAST_MODE
delay(2); // 50x mais rápido para debug
#else
delay(100); // Normal: ~10 loops/seg
#endif
iLED.Alternate(); // Mostra placa viva
FUPump.Update();
for (int i=0; i
Devices.h
// Classes auxiliares para dispositivos IO
extern void printTimeStamp();
class IODevice {
protected:
bool _IsOn;
int _Pin;
String _Name;
public:
IODevice(int pin, String name) { _IsOn = false; _Pin = pin; _Name = name; }
virtual bool IsOn() = 0;
bool IsOff() { return !IsOn(); }
void DebugPrint() { printTimeStamp(); Serial.print(": "); Print(); }
void Print() { Serial.print(_Name); Serial.print(" no pino("); Serial.print(_Pin); if (_IsOn) Serial.println(") = Ligado"); else Serial.println(") = Desligado"); }
};
class Thermostat : public IODevice {
private: int _Counter;
public:
Thermostat(int pin, String name) : IODevice(pin, name) { _Counter = 0; pinMode(_Pin, INPUT_PULLUP); }
virtual bool IsOn() {
if (digitalRead(_Pin) == HIGH && _IsOn) { if (_Counter++ > 5) { _IsOn = false; DebugPrint(); _Counter = 0; } }
else if (digitalRead(_Pin) == LOW && !_IsOn) { if (_Counter++ > 5) { _IsOn = true; DebugPrint(); _Counter = 0; } }
else _Counter = 0;
return _IsOn;
}
};
class Manipulator : public IODevice {
public:
Manipulator(int pin, String name) : IODevice(pin, name) { pinMode(_Pin, OUTPUT); digitalWrite(_Pin, HIGH); }
void On() { if (!_IsOn) { _IsOn = true; digitalWrite(_Pin, LOW); onSwitch(); } }
void Off() { if (_IsOn) { _IsOn = false; digitalWrite(_Pin, HIGH); onSwitch(); } }
virtual void onSwitch() { DebugPrint(); }
virtual bool IsOn() { return _IsOn; }
};
class Valve : public Manipulator {
private: long transitionCount;
public:
Valve(int pin, String name) : Manipulator(pin, name) { transitionCount = 0; }
bool ValveIsOpen() { return (IsOn() && (transitionCount >= VALVE_TIME)); }
void Update() { if (IsOn()) { if (transitionCount < VALVE_TIME) transitionCount++; } else { if (transitionCount > 0) transitionCount--; } }
};
class Pump : public Manipulator {
private: long counter; bool doMaintenance;
public:
Pump(int pin, String name) : Manipulator(pin, name) { counter = 0; doMaintenance = false; }
bool doMaintenanceRun() { return doMaintenance; }
virtual void onSwitch() { Manipulator::onSwitch(); counter = 0; }
void Update() {
if (IsOn()) {
if (counter < PUMP_ACTIVATION_TIME) counter++;
else if (doMaintenance) { printTimeStamp(); Serial.println(": Manutenção bomba concluída"); doMaintenance = false; }
} else {
if (counter < PUMP_MAINTENANCE_TIME) counter++;
else if (!doMaintenance) { printTimeStamp(); Serial.println(": Manutenção bomba necessária"); doMaintenance = true; }
}
}
};
class LED : public Manipulator {
private: long counter;
public:
LED(int pin, String name) : Manipulator(pin, name) { counter = 0; }
virtual void onSwitch() {} // Suprime debug para LEDs
void Alternate() {
#ifdef FAST_MODE
if (counter++ > 250)
#else
if (counter++ > 5)
#endif
{ counter = 0; if (IsOn()) Off(); else On(); }
}
};
Esquemáticos
Fiação detalhada de periféricos (Bomba, Válvulas, Termostatos, LEDs).

Exemplo de fiação de controladores "em cascata". Um controlador por Piso Radiante.

Log real do Monitor Serial para entender funcionalidade. Timestamps mostram delay de 5 min entre abrir válvulas e ligar bomba.
Processo de manufatura
- Controlador de Potência PWM: Construa um Driver de Lâmpada com Modulação de Largura de Pulso
- Sistemas de Aquecimento Solar: De Soluções Passivas a Ativas para Aquecimento Residencial Sustentável
- Monitoramento de Caldeira de Aquecimento Central com Raspberry Pi – Hardware, Software e Guia de Configuração
- Guia Essencial para Manutenção de Lavadora de Pisos para Desempenho Máximo
- Sistema de Iluminação DMX Controlado via Web – Controlador Mestre Arduino
- Assistente de Jogos Automatizado: Dispositivo Inteligente de Automação de Tarefas para Gamers
- Controle USB para Jogos DIY com Arduino – Construa Seu Próprio Gamepad de Alto Desempenho
- Unopad: Controlador MIDI Arduino Perfeito para Ableton Live
- Kit Controlador de Display Fluorescente a Vácuo (VFD) Baseado em Arduino
- Integre seu Aquecimento Central com Arduino para Controle Inteligente