Thermostat commandé via Internet avec arduino Uno, shield Ethernet, RTC et sonde DHT22

Bonjour,
Le projet est maintenant terminé. Il reste à placer les composants dans un boîtier.
Ce thermostat fonctionnant via une liaison Internet est destiné à remplacer un projet qui fonctionne depuis 2017 avec un arduino Yun (ver 1). (Contact "sec" par relais)
Le challenge était d'utiliser du matériel de fond de tiroir (Uno R3, shield Ethernet, RTC, relais, sonde DHT22, diodes led et quelques résistances).
Le remplacement d'un Yun par un Uno engendre évidemment quelques compromis.
La capacité mémoire très limitée du Uno, l'absence d'un système Linux présent sur le Yun, l'obligation de passer par un DynDns, l'absence d'un serveur web local (sur le Uno), une sécurité des transmissions assez faible et une certaine lenteur d'échanges de données.
Solution mise en oeuvre sur le Uno : un serveur d'application json et un traitement des données reçues du client (le client est un serveur web avec scripts php tournant sur un Raspberry pi 3B+ pour les essais). La sécurité est rudimentaire et consiste à utiliser une clé de caractères d'identification.
Si le projet intéresse, je peux publier les codes. (le sketch sur le Uno et le script php sur le serveur web (Apache sur Raspberry pour les essais)).
Le matériel :
1 Arduino Uno R3
1 sonde DHT22
1 module RTC avec pile DS3231
3 résistances de 220 Ohm
1 résistance de 8 kOhm (de 4,7 à 10 kOhm)
3 led (1 verte, 1 jaune, 1 rouge)
1 relais (contact sec avec tension de 220V au secondaire - déclenche le chauffage)
1 condensateur de filtrage de 100 nF
1 ethernet shield avec lecteur carte sd
1 carte sd faible capacité formatée en Fat

Le code pour le Uno :

[code]
#include <SPI.h>
#include <Ethernet.h>
#include "uRTCLib.h"
#include <SD.h>
#include <DHT.h>

#define brocheBranchementDHT 5
#define typeDeDHT DHT22

uRTCLib rtc(0x68);

File filetherm;

// the media access control (ethernet hardware) address for the shield:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  
//the IP address for the shield:
byte ip[] = { XXX,XXX,XXX,XXX }; // introduire l'adresse IP locale du shield Ethernet  
// the router's gateway address:
byte gateway[] = { XXX,XXX,XXX,XXX }; // introduire l'adresse IP du routeur local
// the subnet:
byte subnet[] = { 255, 255, 255, 0 }; 

// server sur port XXXX à introduire en fonction des autorisations de l'hébergeur choisi
EthernetServer server (XXXXX);

char *url = (char *)malloc(10); // L'url recu à stocker
int index = 0;// index indiquant où l'on est rendu dans la chaîne
int maxindex = 0;
char carlu;

boolean ouvert_ferme = false;// true quand relais est fermé

/*  9 valeurs par défaut des 9 variables - index de 0 à 8
0 - int temp_jour_uni = 20;//2 chiiffres max 
1 - int temp_nuit_uni = 7:// 2 chiffres max
2 - int heure_debut_jour = 8;// 2 chiffres max
3 - int min_debut_jour = 0;//2 chiffres max
4 - int heure_debut_nuit = 22;// 2 chiffres max
5 - int min_debut_nuit = 30;// 2 chiffres max
6 - int therm_actif = 0;//1 chiffre 0=non-actif 1=actif
7 - int type_programme 0 1 2 3 = 0;// 1 chiffre
8 - int relai ouvert ou fermé = 0 // 1 chiffre 0=ouvert 1=fermé (cette valeur est uniquement en sortie)
*/
int varint[9];//={20,10,8,0,22,30,0,0,0};// valeurs par défaut;

float temp_sonde;
DHT dht(brocheBranchementDHT, typeDeDHT);
float hyst=0;//valeur hystérisis 0 ou 0.5 -> 0 au setup

void setup()
{
  //// On démarre la voie série pour déboguer
  Serial.begin(9600);
  delay(2000); // wait for console opening
 
  // initialise ethernet device
  
  Ethernet.begin(mac, ip, gateway, subnet);
  // start listening for clients
  server.begin();
  delay(2000); // wait for server opening
    
  boolean lecture=true;
  if (!SD.begin(4)) {
    //Serial.println(F("Initialisation faute!"));
    //// si la lecture des 9 données int sur la carte SD n'est pas possible
    //// valeurs par défaut
    lecture=false;
    }else{
      if (!lecture_sd()){lecture=false;}}
   if (lecture == false){varint[0]=20;varint[1]=10;varint[2]=8;varint[3]=0;varint[4]=23;varint[5]=0;varint[6]=0;varint[7]=0;varint[8]=0;}   
        
   URTCLIB_WIRE.begin(); 
    ////Comment out below line once you set the date & time.
    //// Following line sets the RTC with an explicit date & time
    //// for example to set January 13 2022 at 12:56 you would call:
    //// rtc.set(0, 28, 14, 7, 2, 12, 23);
    //// rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
    //// set day of week (1=Sunday, 7=Saturday) 
    
    
// Initialisation du DHT22;
  dht.begin();
  temp_sonde = dht.readTemperature();
  // pin 4 réservée à SD
  // pin 5 réservée à DHT22
  pinMode(6, OUTPUT);// relais
  pinMode(7, OUTPUT);//led verte
  pinMode(8, OUTPUT);//led jaune
  pinMode(9, OUTPUT);//led rouge
  // pin 10,11,12,13 réservées au Shield Ethernet
  
  digitalWrite(7, HIGH);// led verte allumée
  digitalWrite(8, LOW);// led jaune éteinte
  digitalWrite(9, LOW);// led rouge éteinte
} 

void loop()
{
  
  delay(2000);
  rtc.refresh();
    
  EthernetClient client = server.available();
  if(client.available()){
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: application/json;charset=utf-8");
      client.println("Server: Arduino");
      client.println("Connection: close");
               
      // traitement des infos du client
      index=0;
      while(carlu != '\n') {
        carlu = client.read(); //on lit ce qu'il raconte
        //Serial.print(carlu);
        url[index] = carlu;
        index++;
      }
      //Serial.print(F("\nindex="));
      //Serial.println(index);
      maxindex=index-11;
      carlu = '#';// obligatoire pour le cycle suivant du while
      
      client.println();// ligne vide obligatoire
            
      if (index == 46 || index == 26 || index == 50){
         if (interpreter() == false){page_fin(client);exit;}
      }
      else{
        page_fin(client);exit;
      }
           
      client.println(F("{"));
      client.print(F("\"jour\":"));
      client.print(rtc.day());// indice 0
      client.print(F(",\"mois\":"));
      client.print(rtc.month());// indice 1 
      client.print(F(",\"annee\":"));
      client.print(rtc.year()); // indice 2
      client.print(F(",\"heure\":"));
      client.print(rtc.hour()); // indice 3
      client.print(F(",\"minute\":"));
      client.print(rtc.minute()); // indice 4
      client.print(F(",\"temp_ambiante\":"));
      client.print(temp_sonde);// indice 5
      client.print(F(",\"temp_jour\":")); 
      client.print(varint[0]);// indice 6 sortie/rentrée
      client.print(F(",\"temp_nuit\":"));
      client.print(varint[1]);// indice 7 sortie/rentrée
      client.print(F(",\"heure_debut_jour\":"));
      client.print(varint[2]);// indice 8 sortie/rentrée
      client.print(F(",\"minute_debut_jour\":"));
      client.print(varint[3]);// indice 9 sortie/rentrée
      client.print(F(",\"heure_debut_nuit\":"));
      client.print(varint[4]);// indice 10 sortie/rentrée
      client.print(F(",\"minute_debut_nuit\":"));
      client.print(varint[5]);// indice 11 sortie/rentrée
      client.print(F(",\"therm_actif\":"));
      client.print(varint[6]);// indice 12 sortie/rentrée
      client.print(F(",\"Prog_choix\":"));
      client.print(varint[7]);// indice 13 sortie/rentrée
      client.print(F(",\"relai\":"));
      client.print(varint[8]);// indice 14 sortie
      client.print(F("}"));
      
      delay(1000);
      //Serial.println(F("client stop"));
      client.stop();
    } 
 if (varint[6]==1) // si thermostat actif
  {
    //Serial.println(F("Actions declenchees ..."));
    digitalWrite(8, HIGH);// led jaune allumée
    long temp_demande_jour = varint[0];
    long temp_demande_nuit = varint[1];
    int heure_min_jour_debut = varint[2]*60+varint[3];
    int heure_min_nuit_debut = varint[4]*60+varint[5];
    int Heure_min_actuel = rtc.hour()*60+rtc.minute(); 
    varint[8]=0;ouvert_ferme=false;// relai ouvert
    switch (varint[7]){
    case 0:
      if (heure_min_jour_debut > Heure_min_actuel){
        Serial.println("on est la nuit");
        if (temp_demande_nuit - hyst > temp_sonde){varint[8]=1;
          if (ouvert_ferme==false){ferme_ouvre_relais(true);ouvert_ferme=true;hyst=0;}
        }
        else{ferme_ouvre_relais(false);ouvert_ferme=false;hyst=0.5;}
      }
      
      if (heure_min_jour_debut < Heure_min_actuel && Heure_min_actuel <= heure_min_nuit_debut){
        //Serial.println("on est le jour");
        if (temp_demande_jour - hyst > temp_sonde){varint[8]=1;
          if (ouvert_ferme==false){ferme_ouvre_relais(true);ouvert_ferme=true;hyst=0;}
        }
        else{ferme_ouvre_relais(false);ouvert_ferme=false;hyst=0.5;}
        
      }
      if (heure_min_nuit_debut < Heure_min_actuel  && Heure_min_actuel >= heure_min_jour_debut){
        //Serial.println("on est la nuit");
        if (temp_demande_nuit - hyst > temp_sonde){varint[8]=1;
          if (ouvert_ferme==false){ferme_ouvre_relais(true);ouvert_ferme=true;hyst=0;}
        }
        else{ferme_ouvre_relais(false);ouvert_ferme=false;hyst=0.5;}
      }
    break;
    case 1:
      if (temp_demande_jour - hyst > temp_sonde){varint[8]=1;
          if (ouvert_ferme==false){ferme_ouvre_relais(true);ouvert_ferme=true;hyst=0;}    
      }
      else{ferme_ouvre_relais(false);ouvert_ferme=false;hyst=0.5;}
      
      //Serial.print(F("t.de la sonde = "));
      //Serial.println(temp_sonde);
      //Serial.print(F("t.demandée - hyst = "));
      //float tempa = temp_demande_jour - hyst;
      //Serial.println(tempa);
      
    break;
    case 2:
      if (temp_demande_nuit - hyst > temp_sonde){varint[8]=1;
        if (ouvert_ferme==false){ferme_ouvre_relais(true);ouvert_ferme=true;hyst=0;}
      }
      else{ferme_ouvre_relais(false);ouvert_ferme=false;hyst=0.5;}
    break;
    case 3:
      if (5 - hyst > temp_sonde){varint[8]=1;
        if (ouvert_ferme==false){ferme_ouvre_relais(true);ouvert_ferme=true;hyst=0;}
      }
      else{ferme_ouvre_relais(false);ouvert_ferme=false;hyst=0.5;}
    break;  
  }
 }else{digitalWrite(8, LOW);ferme_ouvre_relais(false);ouvert_ferme=false;}// led jaune éteinte/relais ouvert/led rouge éteinte
 //delay(3000);
 temp_sonde = dht.readTemperature();

} 

boolean interpreter() {
  //Serial.println(F("interpretation"));
  int jj=0;
  boolean chgb = true;
  char k[9] = {'k','a','b','c','d','e','f','g','h'};// clé de connexion à changer !!!!
  
  for (byte i=index-20;i<index-11;i++){  
    //Serial.print(url[i]);
    //Serial.println(k[jj]);
    if (url[i] != k[jj]){chgb = false;}
    jj++;
    }
  // la clé n'est pas valide
  if (chgb == false){
    //Serial.println(F("La cle n'est pas valide"));
    return false;
    }
  
  // fin du traitement du simple aperçu avec simplement la clé approuvée
  if (index == 26){return true;}  
  
  // traitement de l'ajustage de l'heure et de la date à partir du client connecté
  // 5 grandeurs à traiter de 2 chiffres pour former un nombre int donc chaîne de 14 caractères
  // GET /?d
  if (index == 50){
    int varintT[7]; // les 7 variables à introduire
    //Serial.println(F("Ajustage du temps"));
    jj = 7; // passe les 7 premiers caracteres
    for (byte i = 0; i < 7; i++)
      {
        //int chg = varint[i];//valeur de départ
        varintT[i] = int(url[jj] - '0');
        varintT[i] = varintT[i]*10 + int(url[jj+1] - '0');
       
       //Serial.println(varintT[i]);
        jj=jj+2;
      }   
   rtc.set(varintT[0],varintT[1],varintT[2],varintT[3],varintT[4],varintT[5],varintT[6]);
   return true;
  }
  
  // chaîne de 14 chiffres après 10 caractères GET /?com:
  jj = 10; // passe les 10 premiers caractères - 18 caractères suivent = 28 caractères en tout < 29 
  
  chgb=false;
  Serial.println(F("Changement de reglage"));
  for (byte i = 0; i < 8; i++)
  {
    int chg = varint[i];//valeur de départ
    varint[i] = int(url[jj] - '0');
    varint[i] = varint[i]*10 + int(url[jj+1] - '0');
    if (chg != varint[i]){
      Serial.print(F("valeur change "));
      Serial.print(chg);
      Serial.print(F(" <> "));
      Serial.println(varint[i]);
      chgb = true;
      }
    Serial.println(varint[i]);
    jj=jj+2;
   }
   
   if(chgb){ecriture_sd();}
   delay(2000);
   
return true;
}

boolean lecture_sd(){
  //Serial.println(F("Lecture des donnees sur SD"));
  filetherm = SD.open("THERM.TXT");
  
  if (filetherm) {
    //Serial.write(filetherm.read());
    int jj=0;
    int ii=0;
    int chiffre[2];
    while (filetherm.available()){
      char c = filetherm.read();
      if (c != 44){
        //Serial.print(c);
        if (jj==1){
          chiffre[1] = int(c - '0');// jj = 1 2eme chiffre
          varint[ii]=varint[ii]*10+chiffre[1];// 1er chiffre autoatiquement multiplié par 10 + 2ème chifffre unitaire
          }
        if (jj==0){
          chiffre[jj] = int(c - '0');// jj = 0 1er chiffre
          varint[ii]=chiffre[0];// 1er chiffre 
          jj=1;
          }
        }
       if (c == 44){
         jj=0;// jj reprend la valeur 0
         //Serial.println (varint[ii]);
         ii=ii+1;
        }
       if (c == '\n'){break;} 
    }
      // close the file:
    filetherm.close();
    //Serial.println(F("Fin de lecture"));
    return true;
      
  } else {
    //Serial.println(F("erreur ouverture de therm.txt"));
    return false;
  } 
delay(1000);    
return true;    
}

boolean ecriture_sd(){
  //Serial.println(F("Ecriture des donnees sur SD"));
  hyst=0;// remet à 0
  filetherm = SD.open("THERM.TXT",FILE_WRITE);
  if (filetherm) {
    String valeurs = "";
    for (byte ii=0 ; ii < 9 ; ii++){
      valeurs=valeurs+varint[ii]+",";
    }
    filetherm.println(valeurs);
    // close the file:
    filetherm.close();
    //Serial.println(F("Fin d'ecriture"));
    return true;  
    } else {
    // if the file didn't open, print an error:
    //Serial.println(F("Erreur d'ouverture du fichier"));
    return false;
  }
return true;   
}

boolean page_fin(EthernetClient client){
  client.print("Authentification requise !");
  client.stop();
}

boolean ferme_ouvre_relais(boolean etat){
  // change l'état du relai sur pin 6 
  if (etat == true){digitalWrite(6, LOW);digitalWrite(9, HIGH);Serial.println("relai ferme");}// led rouge allumée
  else{digitalWrite(6, HIGH);digitalWrite(9, LOW);Serial.println("relai ouvert");}// led rouge éteinte
}
[/code]

Le fichier zip avec les pages php à placer sur le serveur web (apache avec protection).
Le serveur web d'essai est placé sur un Raspberry pi3b+.
pages_web.zip (11.6 KB)

ça sert à rien de poster ici un "teaser" pour dire ce que vous avez fait
➜ soit vous écrivez une description et partagez le code, soit ce n'est pas la peine de poster :slight_smile:

Les membres de passage aujourd'hui ne sont peut-être pas intéressés mais dans la durée il y aura sans doute des visiteurs

l'idée c'est que vous mettiez un titre parlant et une bonne description du projet pour que les moteurs de recherches trouvent ce post si quelqu'un cherchait "arduino thermostat ethernet" par exemple

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.