Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Système avancé de contrôle de chauffage multi-zones pour maison intelligente

Composants et fournitures

Composant Quantité Notes
Arduino UNO (ou Mega pour >5 zones) 1 Mega recommandé si >5 zones (incl. zone "reste de la maison" sans plancher chauffant)
Carte relais 8 canaux 5 V (Keyes) 1 4 relais pour 2 zones plancher (1 pompe, 1 chaudière, 2 vannes) ; 1 relais supplémentaire par zone extra
Actionneur thermoélectrique Honeywell MT8-230-NC (230 V AC) 1+ 1 actionneur (vanne) par groupe de boucles de plancher. Plusieurs modèles possibles.

À propos de ce projet

J'ai construit ce dispositif car ma cuisine était soit trop chaude, soit trop froide avec un seul thermostat dans le salon. Les contrôleurs multi-zones commerciaux (type EvoHome) sont très chers. Ce programme réplique l'intelligence de ces systèmes coûteux sur un simple Arduino Uno. Problème résolu !

Points forts / Fonctionnalités

Chauffage individuel par zone

Contrôle de la pompe de plancher

Zone "sans plancher" (optionnelle)

Notes finales

Code

ProjectCV.ino (C/C++)

/*
 * Contrôleur chauffage plancher multi-zones v1.0
 * Copyright: GPL-3.0 par Eric Kreuwels, 2017
 * Crédits: Peter Kreuwels pour les cas d'usage
 * Attention: testez avant utilisation réelle !
 */
#include <avr/wdt.h> // Watchdog

// #define FAST_MODE // 50x plus rapide pour test (débranchez pompe/chaudière réelles !)
#define VALVE_TIME 3000L        // 5 min ouverture/fermeture vanne (sécurité)
#ifdef FAST_MODE
#define PUMP_MAINTENANCE_TIME 108000L  // Test: cycle entretien pompe toutes les 4 min (simule 3h)
#else
#define PUMP_MAINTENANCE_TIME 1300000L // Normal: cycle entretien pompe toutes les 36h
#endif
#define PUMP_ACTIVATION_TIME 5000L     // Pompe active ~8 min (10s en test)
#define COOLDOWN_TIME 18000L           // Après chauffe: circulation 30 min (40s test)

#include "./Devices.h" // Classes vannes, pompe, thermostats

struct Zone {
  String name;
  Valve valve;
  Thermostat thermostat;
};

////////////////////////////////////////////////////
// BLOC CONFIGURATION
// Configurez/réordonnez le brochage comme vous voulez (mon câblage sur Uno):
// Note: broches 1 et 2 libres pour zone extra
#define HEATER_PIN 4          // Relais → entrée thermostat chaudière
#define FU_PUMP_PIN 5         // Relais → pompe plancher
#define LIVING_VALVE 7        // Zone 1: relais vanne(s)
#define KITCHEN_VALVE 6       // Zone 2
#define DINING_VALVE 3        // Zone 3
#define LIVING_THERMO 8       // Zone 1: entrée thermostat salon
#define KITCHEN_THERMO 9      // Zone 2: cuisine
#define DINING_THERMO 11      // Zone 3: salle à manger
#define NO_ZONE_THERMO 10     // Optionnel: thermostats pièces sans plancher
#define HEATING_LED 12        // Allumé = chauffe, clignote = refroidissement, éteint = veille
#define INDICATION_LED 13     // Clignote = carte vivante (peut être supprimé pour libérer broche)

#define NR_ZONES 3
Zone Zones[NR_ZONES] = {
  {"Salon", Valve(LIVING_VALVE, "Vanne Salon"), Thermostat(LIVING_THERMO, "Thermo Salon")},
  {"Cuisine", Valve(KITCHEN_VALVE, "Vanne Cuisine"), Thermostat(KITCHEN_THERMO, "Thermo Cuisine")},
  {"Salle a manger", Valve(DINING_VALVE, "Vanne Salle a manger"), Thermostat(DINING_THERMO, "Thermo Salle a manger")}
};
// FIN BLOC CONFIGURATION
////////////////////////////////////////////////////

// Périphériques fixes
LED iLED(INDICATION_LED, "LED Indication");
LED hLED(HEATING_LED, "LED Chauffage");
Manipulator CV(HEATER_PIN, "Chaufferie CV");
Pump FUPump(FU_PUMP_PIN, "Pompe Plancher");
Thermostat ZonelessThermo(NO_ZONE_THERMO, "Thermo Sans Zone");

void printConfiguration() {
  Serial.println("------ Configuration Carte ------");
  iLED.Print(); hLED.Print(); CV.Print(); FUPump.Print(); ZonelessThermo.Print();
  for (int i = 0; i < NR_ZONES; i++) {
    Serial.print("Zone["); Serial.print(i+1); Serial.print("]: "); Serial.println(Zones[i].name);
    Serial.print(" - "); Zones[i].valve.Print();
    Serial.print(" - "); Zones[i].thermostat.Print();
  }
  Serial.println("---------------------------------");
}

// Machine à états : idle, on, cooldown
class State {
public:
  enum states { idle, on, cooldown };
private:
  states _State;
  unsigned long cooldownCount;
public:
  State() : _State(idle) {}

  states getState() const { return _State; }
  void setState(states const& newState) {
    printTimeStamp();
    Serial.print(": Changement d'etat [");
    printState(_State);
    _State = newState;
    Serial.print("] vers [");
    printState(_State);
    Serial.println("]");

    switch (_State) {
      case idle: hLED.Off(); CV.Off(); FUPump.Off(); allValvesOff(); break;
      case on:   hLED.On();  CV.On();  break; // pompe attend ouverture vanne
      case cooldown: CV.Off(); allValvesOn(); break; // pompe attend ouverture
    }
  }

  void doProcessingActions() {
    switch (_State) {
      case on:       onProcessing(); break;
      case cooldown: coolDownProcessing(); break;
      case idle:     idleProcessing(); break;
    }
  }

  void setCoolDownNeeded() { cooldownCount = COOLDOWN_TIME; }
  bool whileCoolDownNeeded() {
    if (cooldownCount > 0) cooldownCount--;
    return checkCoolDownNeeded();
  }
  bool checkCoolDownNeeded() { return (cooldownCount > 0); }

  void printState(states s) {
    switch (s) { case idle: Serial.print("idle"); break; case on: Serial.print("on"); break; case cooldown: Serial.print("cooldown"); break; }
  }
};

State CVState;

void setup() {
  Serial.begin(115200);
  printTimeStamp(); Serial.print(": ");
#ifdef FAST_MODE
  Serial.println("Controleur zones CV demarre en Mode Test!\n - Temps carte ~50x plus vite\n - Maintenance pompe toutes les 3h au lieu de 36h");
#else
  Serial.println("Controleur zones CV demarre. Horodatage (jj:hh:mm:ss)");
#endif
  Serial.println(" - Format horodatage (jj:hh:mm:ss)");
  printConfiguration();
  wdt_enable(WDTO_1S); // Watchdog: reset si pas "caressé" dans 1s
}

void loop() {
#ifdef FAST_MODE
  delay(2);
#else
  delay(100); // ~10 boucles/sec
#endif

  iLED.Alternate(); // vie de la carte
  FUPump.Update();
  for (int i = 0; i < NR_ZONES; i++) Zones[i].valve.Update();
  wdt_reset(); // caresse le watchdog
  CVState.doProcessingActions();
}

//////////////////////////////////
// Méthodes de traitement par état
////////////////////////////////
void onProcessing() {
  if (ProcessThermostats()) { // true si au moins un thermostat demande chauffe
    if (FloorPumpingAllowed()) FUPump.On(); else FUPump.Off();
  } else if (CVState.checkCoolDownNeeded()) {
    CVState.setState(State::cooldown);
  } else {
    CVState.setState(State::idle);
  }
}

void coolDownProcessing() {
  hLED.Alternate();
  if (HeatingRequested()) {
    CVState.setState(State::on);
  } else {
    if (CVState.whileCoolDownNeeded()) {
      if (FloorPumpingAllowed()) FUPump.On(); else FUPump.Off();
    } else {
      CVState.setState(State::idle);
    }
  }
}

void idleProcessing() {
  if (HeatingRequested()) {
    CVState.setState(State::on);
  } else {
    if (FUPump.doMaintenanceRun()) {
      if (FUPump.IsOff()) {
        if (!allValvesOpen()) {
          printTimeStamp(); Serial.println(": Debut cycle journalier pompe; ouverture vannes");
          allValvesOn();
        }
        if (FloorPumpingAllowed()) {
          printTimeStamp(); Serial.println(": Debut cycle journalier pompe; demarrage pompe");
          FUPump.On();
        }
      }
    } else if (FUPump.IsOn()) {
      printTimeStamp(); Serial.println(": Fin cycle journalier pompe; arret pompe et fermeture vannes");
      FUPump.Off(); allValvesOff();
    }
  }
}

//////////////////////////////////
// Méthodes utilitaires
////////////////////////////////
void allValvesOff() { for (int i=0;i

Devices.h (C/C++)


// Classes utilitaires pour périphériques E/S
extern void printTimeStamp(); // défini dans le .ino principal

// Classe de base
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(" sur broche("); Serial.print(_Pin);
    if (_IsOn) Serial.println(") = On"); else Serial.println(") = Off");
  }
};

// Thermostat : entrée numérique avec anti-rebond
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;
  }
};

// Manipulateur : sortie numérique basique
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; }
};

// Vanne : sortie avec gestion temps de transition (3-5 min)
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--; }
  }
};

// Pompe : cycles d'entretien périodiques
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(": Maintenance pompe terminee"); doMaintenance = false; }
    } else {
      if (counter < PUMP_MAINTENANCE_TIME) counter++;
      else if (!doMaintenance) { printTimeStamp(); Serial.println(": Maintenance pompe necessaire"); doMaintenance = true; }
    }
  }
};

// LED : On/Off + alternance 1Hz
class LED : public Manipulator {
private:
  long counter;
public:
  LED(int pin, String name) : Manipulator(pin, name) { counter = 0; }
  virtual void onSwitch() {} // pas de debug pour LEDs
  void Alternate() {
#ifdef FAST_MODE
    if (counter++ > 250)
#else
    if (counter++ > 5)
#endif
    { counter = 0; if (IsOn()) Off(); else On(); }
  }
};

Schémas

  • Câblage détaillé des périphériques (Pompe, Vannes, Thermostats, LEDs) — image fournie
  • Exemple de câblage de contrôleurs "en cascade" (un par plancher) — image fournie
  • Extrait de logs série réels (horodatages montrent délai 5 min entre ouverture vannes et démarrage pompe) — fichier logexample_fTczkAa0tf.txt

Processus de fabrication

  1. Contrôleur de puissance PWM : construction d'un driver de lampe à modulation de largeur d'impulsion
  2. Systèmes de chauffage solaire : des solutions passives aux actives pour un chauffage domestique durable
  3. Surveillance de votre chaudière centrale avec Raspberry Pi – Matériel, Logiciel et Guide de configuration
  4. Guide essentiel pour maintenir votre autolaveuse à performance optimale
  5. Système d'éclairage DMX piloté par web – Contrôleur maître Arduino
  6. Assistant de jeu automatisé : Dispositif intelligent d'automatisation de tâches pour gamers
  7. Manette de jeu USB Arduino DIY – Construisez votre propre gamepad haute performance
  8. Unopad : contrôleur MIDI Arduino fluide pour Ableton Live
  9. Kit contrôleur d'affichage VFD (afficheur fluorescent sous vide) basé sur Arduino