un exemple de restructuration du code pour qu'il soit plus lisible, ne continent pas de while true qui sont toujours un risque, création de fonctions pour simplifier la lecture etc...
Notez que vous utilisez une vous utilisez aussi une version de IRremote qui est obsolète... faudrait passer à la nouvelle API...
➜ GitHub - Arduino-IRremote/Arduino-IRremote: Infrared remote library for Arduino: send and receive infrared signals with multiple protocols · GitHub
// SpaDUino v1.71 — Gestion d'un SPA/Jacuzzi
// Auteur original : Nicolas Lecerf
// Adaptation : François Huot, avril 2026
// Licence : BY NC SA
// ═══════════════════════════════════════════════════════════════════════════
// BIBLIOTHÈQUES
// ═══════════════════════════════════════════════════════════════════════════
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <RTClib.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>
#include <OneWire.h>
#include <IRremote.h>
// ═══════════════════════════════════════════════════════════════════════════
// BROCHES
// ═══════════════════════════════════════════════════════════════════════════
const int BROCHE_SONDE_TEMP = 6;
const int BROCHE_IR = 9;
const int BROCHE_BT_RX = 10;
const int BROCHE_BT_TX = 11;
const int BROCHE_POMPE_PV = 2;
const int BROCHE_POMPE_GV = 3;
const int BROCHE_RESISTANCE = 4;
const int BROCHE_COMMUN_POMPE = 5;
const int BROCHE_BULLEUR = A0;
const int BROCHE_LAMPE_INT = A1;
const int BROCHE_LAMPE_EXT = A2;
const int BROCHE_LAMPE_JARDIN = A3;
const int BROCHE_CREPUSCULAIRE = A6;
// ═══════════════════════════════════════════════════════════════════════════
// CONFIGURATION (à ajuster selon installation)
// ═══════════════════════════════════════════════════════════════════════════
const int SEUIL_CREPUSCULAIRE = 300;
const int TEMP_MAXI = 37;
const int TEMP_MINI = 28;
const int TEMP_CONSIGNE_DEFAUT = 32;
const int DUREE_FORCEE_POMPE_MIN = 15; // minutes
const int DUREE_FORCEE_LAMPE_H = 2; // heures
const int DELAI_FILTRE_JET_J = 7; // jours
const int DELAI_FILTRE_HP_J = 21; // jours
const int HEURE_FIN_ECLAIRAGE = 23;
const int PLAGE_FILTRATION[2][2] = { { 2, 5 }, { 12, 14 } };
const float VERSION = 1.71;
// Codes IR télécommande
const unsigned long IR_MASSAGE1 = 0xFD00FF;
const unsigned long IR_TEMP_PLUS = 0xFD8877;
const unsigned long IR_TEMP_MOINS = 0xFD9867;
const unsigned long IR_MENU = 0xFD609F;
const unsigned long IR_LAMPE_INT = 0xFD10EF;
const unsigned long IR_LAMPE_EXT = 0xFD906F;
const unsigned long IR_JARDIN = 0xFD50AF;
const unsigned long IR_POMPE_PV = 0xFD30CF;
const unsigned long IR_BULLEUR = 0xFDB04F;
const unsigned long IR_POMPE_GV = 0xFD708F;
const unsigned long IR_OK = 0xFDA857;
const unsigned long IR_ECRAN = 0xFD40BF;
const unsigned long IR_BUG = 0xFFFFFFFF;
// ═══════════════════════════════════════════════════════════════════════════
// OBJETS MATÉRIELS
// ═══════════════════════════════════════════════════════════════════════════
OneWire busTemp(BROCHE_SONDE_TEMP);
DallasTemperature sondeTemp(&busTemp);
SoftwareSerial bluetooth(BROCHE_BT_RX, BROCHE_BT_TX);
RTC_DS3231 horloge;
hd44780_I2Cexp ecran;
IRrecv recepteurIR(BROCHE_IR);
decode_results signalIR;
const int LCD_COLS = 20;
const int LCD_LIGNES = 4;
// ═══════════════════════════════════════════════════════════════════════════
// VARIABLES GLOBALES
// ═══════════════════════════════════════════════════════════════════════════
DateTime maintenant;
char nomJours[7][12] = { "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi" };
int tempActuelle = 0;
int consigneTemp = TEMP_CONSIGNE_DEFAUT;
int valeurCrepuscule = 0;
bool chauffageActif = false;
bool pompeChauffage = false;
bool eclairageActif = false;
bool aerationActive = false;
bool retroEclairage = true;
bool lampeForceeInt = false;
bool lampeForceeExt = false;
bool lampeForceeJardin = false;
bool pumpPvForcee = false;
bool bulleurForce = false;
bool pompeGvForcee = false;
bool pompeGvActive = false;
bool pompePvActive = false;
bool alerteFiltreJet = false;
bool alerteFiltreHP = false;
bool filtrationActive = false;
DateTime finMarcheForceePompe;
DateTime finMarcheForceeLampe;
DateTime prochainNettoyageJet;
DateTime prochainNettoyageHP;
String messageRecu;
// ═══════════════════════════════════════════════════════════════════════════
// UTILITAIRES
// ═══════════════════════════════════════════════════════════════════════════
// Affiche un nombre sur 2 chiffres (avec zéro initial si besoin)
void afficherDeuxChiffres(int valeur) {
if (valeur <= 9) ecran.print("0");
ecran.print(valeur);
}
// Imprime hh:mm:ss d'un DateTime sur le LCD
void afficherHeure(DateTime dt) {
afficherDeuxChiffres(dt.hour());
ecran.print(":");
afficherDeuxChiffres(dt.minute());
ecran.print(":");
afficherDeuxChiffres(dt.second());
}
// Imprime jj/mm d'un DateTime sur le LCD
void afficherDateCourte(DateTime dt) {
if (dt.day() <= 9) ecran.print('0');
ecran.print(dt.day());
ecran.print('/');
if (dt.month() <= 9) ecran.print('0');
ecran.print(dt.month());
}
// Nettoie le signal IR et remet results.value à zéro
void nettoyerIR() {
Serial.print("nettoyage IR : ");
Serial.println(signalIR.value, HEX);
recepteurIR.resume();
signalIR.value = 0;
delay(100);
}
// Reçoit un éventuel message Bluetooth dans messageRecu
void lireBluetooth() {
messageRecu = "";
while (bluetooth.available()) {
delay(3);
messageRecu += (char)bluetooth.read();
}
if (messageRecu.length() > 0)
Serial.println(messageRecu);
}
// Envoie l'état du spa au module Bluetooth
void envoyerBluetooth() {
bluetooth.print("*T" + String(tempActuelle) + "*");
bluetooth.print("*C" + String(consigneTemp) + "*");
bluetooth.print(chauffageActif ? "*RR255G0B0*" : "*RR255G255B255*");
if (alerteFiltreJet) bluetooth.print("*MNettoyage filtre Jet*");
else if (alerteFiltreHP) bluetooth.print("*MNettoyage filtre HP*");
else if (filtrationActive) bluetooth.print("*MFiltration en cours*");
else if (aerationActive) bluetooth.print("*MAeration en cours*");
else bluetooth.print("*MSpaduino*");
}
// Lit la température de la sonde et met à jour tempActuelle
void lireTemperature() {
sondeTemp.requestTemperatures();
tempActuelle = (int)sondeTemp.getTempCByIndex(0);
}
// ═══════════════════════════════════════════════════════════════════════════
// AFFICHAGE LCD
// ═══════════════════════════════════════════════════════════════════════════
void afficherEtatGeneral() {
ecran.setCursor(0, 0);
if (alerteFiltreHP) ecran.print("**Nettoie Filtre HP**");
else if (alerteFiltreJet) ecran.print("**Nettoie Filtre Jet*");
else if (filtrationActive) ecran.print("*****Filtration*****");
else {
ecran.print("SpaDuino - ");
ecran.print(nomJours[maintenant.dayOfTheWeek()]);
}
}
void afficherDateHeure() {
ecran.setCursor(0, 1);
ecran.print(maintenant.day());
ecran.print("/");
ecran.print(maintenant.month());
ecran.print("/");
ecran.print(maintenant.year());
ecran.print("-");
afficherDeuxChiffres(maintenant.hour());
ecran.print(":");
afficherDeuxChiffres(maintenant.minute());
ecran.print(":");
afficherDeuxChiffres(maintenant.second());
}
void afficherTemperatures() {
ecran.setCursor(0, 2);
ecran.print("Temp:");
ecran.print(tempActuelle);
ecran.print("C/");
ecran.print(consigneTemp);
ecran.print("C");
}
void afficherActionneurs() {
ecran.setCursor(0, 3);
ecran.print("Ch:");
ecran.print(chauffageActif);
ecran.print(" Ecl:");
ecran.print(eclairageActif);
ecran.print(" PV:");
ecran.print(pompePvActive);
ecran.print(" GV:");
ecran.print(pompeGvActive);
}
void afficherEcran() {
if (maintenant.hour() == 0 && maintenant.minute() == 0 && maintenant.second() == 0)
ecran.clear();
afficherEtatGeneral();
afficherDateHeure();
afficherTemperatures();
afficherActionneurs();
}
void afficherDebugSerie() {
Serial.print("Il est : ");
Serial.print(maintenant.hour());
Serial.print(":");
if (maintenant.minute() <= 9) Serial.print("0");
Serial.print(maintenant.minute());
Serial.print(":");
if (maintenant.second() <= 9) Serial.print("0");
Serial.println(maintenant.second());
Serial.print("Temperature : ");
Serial.println(tempActuelle);
Serial.print("Crepusculaire : ");
Serial.println(valeurCrepuscule);
}
// ═══════════════════════════════════════════════════════════════════════════
// GESTION FILTRATION
// ═══════════════════════════════════════════════════════════════════════════
void gererAlerteFiltre() {
if (prochainNettoyageHP.day() == maintenant.day()
&& prochainNettoyageHP.month() == maintenant.month()
&& prochainNettoyageHP.minute() == maintenant.minute())
alerteFiltreHP = true;
if (prochainNettoyageJet.day() == maintenant.day()
&& prochainNettoyageJet.month() == maintenant.month()
&& prochainNettoyageJet.minute() == maintenant.minute())
alerteFiltreJet = true;
}
void gererFiltration() {
filtrationActive =
(maintenant.hour() >= PLAGE_FILTRATION[0][0] && maintenant.hour() < PLAGE_FILTRATION[0][1]) || (maintenant.hour() >= PLAGE_FILTRATION[1][0] && maintenant.hour() < PLAGE_FILTRATION[1][1]);
}
// ═══════════════════════════════════════════════════════════════════════════
// GESTION ÉCLAIRAGE
// ═══════════════════════════════════════════════════════════════════════════
void gererEclairage() {
valeurCrepuscule = analogRead(BROCHE_CREPUSCULAIRE);
bool nuit = (valeurCrepuscule <= SEUIL_CREPUSCULAIRE
&& maintenant.hour() >= 17
&& maintenant.hour() < HEURE_FIN_ECLAIRAGE);
// Lampe extérieure spa
bool allumerExt = nuit || lampeForceeExt;
digitalWrite(BROCHE_LAMPE_EXT, allumerExt ? LOW : HIGH);
// Lampe jardin
bool allumerJardin = nuit || lampeForceeJardin;
digitalWrite(BROCHE_LAMPE_JARDIN, allumerJardin ? LOW : HIGH);
eclairageActif = allumerExt || allumerJardin;
// Arrêt automatique lampes forcées
if (finMarcheForceeLampe.hour() == maintenant.hour()) {
digitalWrite(BROCHE_LAMPE_INT, HIGH);
digitalWrite(BROCHE_LAMPE_EXT, HIGH);
digitalWrite(BROCHE_LAMPE_JARDIN, HIGH);
lampeForceeInt = lampeForceeExt = lampeForceeJardin = false;
}
}
// ═══════════════════════════════════════════════════════════════════════════
// GESTION POMPES
// ═══════════════════════════════════════════════════════════════════════════
void gererPompes() {
// Arrêt automatique marche forcée pompes
if (finMarcheForceePompe.minute() == maintenant.minute()) {
digitalWrite(BROCHE_POMPE_GV, LOW);
digitalWrite(BROCHE_COMMUN_POMPE, LOW);
digitalWrite(BROCHE_BULLEUR, HIGH);
pompeGvActive = pompeGvForcee = pumpPvForcee = bulleurForce = false;
}
// Pompe petite vitesse : active si filtration, marche forcée ou chauffage en cours
if (filtrationActive || pumpPvForcee || pompeChauffage) {
if (!pompeGvActive) {
pompePvActive = true;
digitalWrite(BROCHE_POMPE_PV, HIGH);
digitalWrite(BROCHE_COMMUN_POMPE, HIGH);
}
} else if (!pompeGvForcee) {
pompePvActive = false;
digitalWrite(BROCHE_POMPE_PV, LOW);
digitalWrite(BROCHE_COMMUN_POMPE, LOW);
}
}
// ═══════════════════════════════════════════════════════════════════════════
// GESTION CHAUFFAGE
// ═══════════════════════════════════════════════════════════════════════════
void gererChauffage() {
if (tempActuelle <= consigneTemp - 1) {
pompeChauffage = true;
if (!chauffageActif) delay(3000); // pause avant premier allumage résistance
if (pompePvActive || pompeGvActive) {
digitalWrite(BROCHE_RESISTANCE, HIGH);
chauffageActif = true;
}
}
if (tempActuelle >= consigneTemp + 1) {
if (chauffageActif) delay(5000); // pause avant extinction résistance
digitalWrite(BROCHE_RESISTANCE, LOW);
chauffageActif = false;
pompeChauffage = false;
}
}
// ═══════════════════════════════════════════════════════════════════════════
// AÉRATION JOURNALIÈRE
// ═══════════════════════════════════════════════════════════════════════════
void programmeAeration() {
ecran.clear();
ecran.setCursor(0, 1);
ecran.print("SpaDuino - Aeration");
digitalWrite(BROCHE_POMPE_GV, LOW);
digitalWrite(BROCHE_BULLEUR, LOW);
digitalWrite(BROCHE_POMPE_PV, HIGH);
digitalWrite(BROCHE_COMMUN_POMPE, HIGH);
delay(59990);
digitalWrite(BROCHE_BULLEUR, HIGH);
digitalWrite(BROCHE_POMPE_PV, LOW);
digitalWrite(BROCHE_COMMUN_POMPE, LOW);
}
void gererAeration() {
if (pompeGvActive) return;
if ((maintenant.hour() == 8 && maintenant.minute() == 0) || (maintenant.hour() == 13 && maintenant.minute() == 0) || (maintenant.hour() == 19 && maintenant.minute() == 0))
programmeAeration();
}
// ═══════════════════════════════════════════════════════════════════════════
// MENU FILTRE
// ═══════════════════════════════════════════════════════════════════════════
void afficherMenuFiltre() {
ecran.setCursor(0, 0);
ecran.print(" Nettoyage Filtre ");
ecran.setCursor(0, 1);
ecran.print("Jet:");
afficherDateCourte(prochainNettoyageJet);
ecran.print(" - HP:");
afficherDateCourte(prochainNettoyageHP);
ecran.setCursor(0, 2);
ecran.print("1:Jet 2:HP - V");
ecran.print(VERSION);
ecran.setCursor(0, 3);
ecran.print("3:Ecran OK:Exit ");
}
void afficherConfirmationRAZ() {
ecran.clear();
ecran.setCursor(0, 0);
ecran.print("confirmer RAZ ");
ecran.setCursor(0, 1);
ecran.print("OK ou 0 pour annuler");
}
// Attend une confirmation OK ou annulation 0 ; retourne true si confirmé
bool attendreConfirmation() {
bool reponse = false;
bool enAttente = true;
while (enAttente) {
lireBluetooth();
if (recepteurIR.decode(&signalIR) || messageRecu.length() > 0) {
if (signalIR.value == IR_OK || messageRecu == "OK") {
reponse = true;
enAttente = false;
} else if (signalIR.value == IR_BULLEUR || messageRecu == "0") {
reponse = false;
enAttente = false;
} else if (signalIR.value == IR_BUG) {
nettoyerIR();
}
}
delay(100);
}
delay(100);
recepteurIR.resume();
ecran.clear();
return reponse;
}
void menuFiltre() {
DateTime maintenant = horloge.now();
ecran.clear();
afficherMenuFiltre();
nettoyerIR();
bool dansMenu = true;
while (dansMenu) {
lireBluetooth();
if (recepteurIR.decode(&signalIR) || messageRecu.length() > 0) {
if (signalIR.value == IR_MASSAGE1 || messageRecu == "1") { // reset filtre Jet
nettoyerIR();
afficherConfirmationRAZ();
if (attendreConfirmation()) {
alerteFiltreJet = false;
prochainNettoyageJet = maintenant + TimeSpan(DELAI_FILTRE_JET_J, 0, 0, 0);
}
dansMenu = false;
} else if (signalIR.value == 0xFD807F || messageRecu == "2") { // reset filtre HP
nettoyerIR();
afficherConfirmationRAZ();
if (attendreConfirmation()) {
alerteFiltreHP = false;
prochainNettoyageHP = maintenant + TimeSpan(DELAI_FILTRE_HP_J, 0, 0, 0);
}
dansMenu = false;
} else if (signalIR.value == IR_OK || messageRecu == "OK") { // quitter
nettoyerIR();
ecran.clear();
dansMenu = false;
} else if (signalIR.value == IR_ECRAN || messageRecu == "3") { // bascule rétroéclairage
nettoyerIR();
retroEclairage = !retroEclairage;
ecran.setBacklight(retroEclairage ? HIGH : LOW);
ecran.clear();
dansMenu = false;
} else if (signalIR.value == IR_BUG) {
nettoyerIR();
}
}
delay(100);
}
}
// ═══════════════════════════════════════════════════════════════════════════
// PROGRAMME MASSAGE 1
// ═══════════════════════════════════════════════════════════════════════════
void arreterMassage() {
digitalWrite(BROCHE_POMPE_GV, LOW);
digitalWrite(BROCHE_COMMUN_POMPE, LOW);
pompeGvActive = false;
digitalWrite(BROCHE_RESISTANCE, LOW);
digitalWrite(BROCHE_BULLEUR, HIGH);
ecran.clear();
}
void programmeMassage1() {
const int DUREE_MASSAGE_MIN = 15;
const int DUREE_BULLEUR_MARCHE_SEC = 45;
const int DUREE_BULLEUR_ARRET_MIN = 3;
const int CONSIGNE_TEMP_MASSAGE = 35;
messageRecu = "";
DateTime maintenant = horloge.now();
DateTime heureFinMassage = maintenant + TimeSpan(0, 0, DUREE_MASSAGE_MIN, 0);
DateTime prochainDebutBulleur = maintenant + TimeSpan(0, 0, DUREE_BULLEUR_ARRET_MIN, 0);
DateTime prochainArretBulleur = maintenant; // initialisé dans le passé immédiat
ecran.clear();
ecran.setCursor(0, 0);
ecran.print("**Cycle Massage 1***");
delay(200);
bool massageEnCours = true;
while (massageEnCours) {
lireTemperature();
maintenant = horloge.now();
// Affichage
ecran.setCursor(0, 1);
ecran.print("Il est : ");
afficherHeure(maintenant);
ecran.setCursor(0, 2);
ecran.print("Fin a : ");
afficherHeure(heureFinMassage);
ecran.setCursor(0, 3);
ecran.print("Temp : ");
ecran.print(tempActuelle);
ecran.print("C/");
ecran.print(CONSIGNE_TEMP_MASSAGE);
ecran.print("C");
// Pompe GV
digitalWrite(BROCHE_POMPE_GV, HIGH);
digitalWrite(BROCHE_COMMUN_POMPE, HIGH);
// Chauffage
if (tempActuelle <= CONSIGNE_TEMP_MASSAGE - 1) digitalWrite(BROCHE_RESISTANCE, HIGH);
if (tempActuelle >= CONSIGNE_TEMP_MASSAGE + 1) digitalWrite(BROCHE_RESISTANCE, LOW);
// Bulleur — allumage
if (maintenant.minute() == prochainDebutBulleur.minute()
&& maintenant.second() == prochainDebutBulleur.second()) {
digitalWrite(BROCHE_BULLEUR, LOW);
prochainArretBulleur = maintenant + TimeSpan(0, 0, 0, DUREE_BULLEUR_MARCHE_SEC);
}
// Bulleur — extinction
if (maintenant.minute() == prochainArretBulleur.minute()
&& maintenant.second() == prochainArretBulleur.second()) {
digitalWrite(BROCHE_BULLEUR, HIGH);
prochainDebutBulleur = maintenant + TimeSpan(0, 0, DUREE_BULLEUR_ARRET_MIN, 0);
}
lireBluetooth();
// Fin par le temps
if (heureFinMassage.minute() == maintenant.minute()
&& heureFinMassage.second() == maintenant.second())
massageEnCours = false;
// Annulation télécommande (touche 0) ou BT
if (recepteurIR.decode(&signalIR) || messageRecu.length() > 0) {
if (signalIR.value == IR_BULLEUR || messageRecu == "massage1") {
delay(100);
recepteurIR.resume();
massageEnCours = false;
} else if (signalIR.value == IR_BUG) {
nettoyerIR();
}
}
messageRecu = "";
delay(10);
}
arreterMassage();
}
// ═══════════════════════════════════════════════════════════════════════════
// GESTION DES COMMANDES IR / BLUETOOTH
// ═══════════════════════════════════════════════════════════════════════════
void gererCommandes() {
lireBluetooth();
if (!recepteurIR.decode(&signalIR) && messageRecu.length() == 0) return;
Serial.print("Code IR : ");
Serial.println(signalIR.value, HEX);
Serial.print("Message BT : ");
Serial.println(messageRecu);
// ── Massage 1 ────────────────────────────────────────────────────────────
if (signalIR.value == IR_MASSAGE1 || messageRecu == "massage1") {
ecran.clear();
recepteurIR.resume();
digitalWrite(BROCHE_POMPE_PV, LOW);
digitalWrite(BROCHE_POMPE_GV, LOW);
digitalWrite(BROCHE_COMMUN_POMPE, LOW);
digitalWrite(BROCHE_BULLEUR, HIGH);
digitalWrite(BROCHE_RESISTANCE, LOW);
programmeMassage1();
}
// ── Consigne température ─────────────────────────────────────────────────
if (signalIR.value == IR_TEMP_PLUS || messageRecu == "temp+") {
if (consigneTemp < TEMP_MAXI) consigneTemp++;
}
if (signalIR.value == IR_TEMP_MOINS || messageRecu == "temp-") {
if (consigneTemp > TEMP_MINI) consigneTemp--;
}
// ── Menu filtre ──────────────────────────────────────────────────────────
if (signalIR.value == IR_MENU || messageRecu == "menu") {
ecran.clear();
recepteurIR.resume();
menuFiltre();
}
// ── Lampe intérieure ─────────────────────────────────────────────────────
if (signalIR.value == IR_LAMPE_INT || messageRecu == "lampeSpaInt") {
lampeForceeInt = !lampeForceeInt;
if (lampeForceeInt) {
finMarcheForceeLampe = maintenant + TimeSpan(0, DUREE_FORCEE_LAMPE_H, 0, 0);
digitalWrite(BROCHE_LAMPE_INT, LOW);
} else {
digitalWrite(BROCHE_LAMPE_INT, HIGH);
}
}
// ── Lampe extérieure ─────────────────────────────────────────────────────
if (signalIR.value == IR_LAMPE_EXT || messageRecu == "lampeSpaExt") {
lampeForceeExt = !lampeForceeExt;
if (lampeForceeExt)
finMarcheForceeLampe = maintenant + TimeSpan(0, DUREE_FORCEE_LAMPE_H, 0, 0);
}
// ── Lampe jardin ─────────────────────────────────────────────────────────
if (signalIR.value == IR_JARDIN || messageRecu == "lampeJardin") {
lampeForceeJardin = !lampeForceeJardin;
if (lampeForceeJardin)
finMarcheForceeLampe = maintenant + TimeSpan(0, DUREE_FORCEE_LAMPE_H, 0, 0);
}
// ── Pompe petite vitesse ─────────────────────────────────────────────────
if (signalIR.value == IR_POMPE_PV || messageRecu == "pompePV") {
if (!pumpPvForcee && !pompeGvActive) {
finMarcheForceePompe = maintenant + TimeSpan(0, 0, DUREE_FORCEE_POMPE_MIN, 0);
pumpPvForcee = true;
} else {
pumpPvForcee = false;
}
}
// ── Bulleur ──────────────────────────────────────────────────────────────
if (signalIR.value == IR_BULLEUR || messageRecu == "bulleur") {
bulleurForce = !bulleurForce;
if (bulleurForce) {
finMarcheForceePompe = maintenant + TimeSpan(0, 0, DUREE_FORCEE_POMPE_MIN, 0);
digitalWrite(BROCHE_BULLEUR, LOW);
} else {
digitalWrite(BROCHE_BULLEUR, HIGH);
}
}
// ── Pompe grande vitesse ─────────────────────────────────────────────────
if (signalIR.value == IR_POMPE_GV || messageRecu == "pompeGV") {
pompeGvForcee = !pompeGvForcee;
if (pompeGvForcee) {
finMarcheForceePompe = maintenant + TimeSpan(0, 0, DUREE_FORCEE_POMPE_MIN, 0);
pompeGvActive = true;
digitalWrite(BROCHE_POMPE_GV, HIGH);
digitalWrite(BROCHE_COMMUN_POMPE, HIGH);
} else {
pompeGvActive = false;
digitalWrite(BROCHE_POMPE_GV, LOW);
}
}
recepteurIR.resume();
nettoyerIR();
messageRecu = "";
}
// ═══════════════════════════════════════════════════════════════════════════
// SETUP
// ═══════════════════════════════════════════════════════════════════════════
void setup() {
Serial.begin(115200);
int erreurLcd = ecran.begin(LCD_COLS, LCD_LIGNES);
if (erreurLcd) {
Serial.print("Erreur init LCD : ");
Serial.println(erreurLcd);
hd44780::fatalError(erreurLcd);
}
ecran.setBacklight(HIGH);
sondeTemp.begin();
pinMode(BROCHE_POMPE_PV, OUTPUT);
digitalWrite(BROCHE_POMPE_PV, LOW);
pinMode(BROCHE_POMPE_GV, OUTPUT);
digitalWrite(BROCHE_POMPE_GV, LOW);
pinMode(BROCHE_COMMUN_POMPE, OUTPUT);
digitalWrite(BROCHE_COMMUN_POMPE, LOW);
pinMode(BROCHE_RESISTANCE, OUTPUT);
digitalWrite(BROCHE_RESISTANCE, LOW);
pinMode(BROCHE_BULLEUR, OUTPUT);
digitalWrite(BROCHE_BULLEUR, HIGH);
pinMode(BROCHE_LAMPE_INT, OUTPUT);
digitalWrite(BROCHE_LAMPE_INT, HIGH);
pinMode(BROCHE_LAMPE_EXT, OUTPUT);
digitalWrite(BROCHE_LAMPE_EXT, HIGH);
pinMode(BROCHE_LAMPE_JARDIN, OUTPUT);
digitalWrite(BROCHE_LAMPE_JARDIN, HIGH);
recepteurIR.enableIRIn();
bluetooth.begin(9600);
delay(1000);
// Décommenter une seule fois pour remettre l'horloge à l'heure :
// horloge.adjust(DateTime(F(__DATE__), F(__TIME__)));
maintenant = horloge.now();
prochainNettoyageJet = maintenant + TimeSpan(0, 0, 2, 0);
prochainNettoyageHP = maintenant + TimeSpan(0, 0, 1, 0);
Serial.print("SpaDuino Version ");
Serial.println(VERSION);
Serial.println("Initialisation OK");
}
// ═══════════════════════════════════════════════════════════════════════════
// LOOP
// ═══════════════════════════════════════════════════════════════════════════
void loop() {
lireTemperature();
envoyerBluetooth();
maintenant = horloge.now();
afficherEcran();
afficherDebugSerie();
gererCommandes();
gererAlerteFiltre();
gererFiltration();
gererEclairage();
gererPompes();
gererChauffage();
gererAeration();
}
(note = j'ai demandé à l'IA, en lui donnant des conseils précis, de restructurer votre code. J'ai pas testé si le résultat est fonctionnel, donc l'objectif est plutôt de vous montrer à quoi peut ressembler un code structuré "correctement")