Automatisation box culture

Bonjour a tous !
Passionné par l'électronique et les plantes j'ai trouvé de quoi m'occuper un moment !
J'ai une box de culture avec dedans rosier orchidées, bonzaïs, tomates, fraises(hum....)

Bref tout ca pour dire que j'ai automatisé via une arduino certaines choses:
-Extinction/allumage d'une lampe cfl jour nuit.
-Allumage/extinction intracteur extracteur d'air.
-Allumage extinction chauffage

Eclairage : 10h 22h
Ventilation : 30mn/h jour /// 15mn/h nuit
chauffage : 22°C Jour 15°C nuit

La matériel que j'ai utilisé :
-Arduino uno
-Horloge rtc pour la gestion du temps
-sonde de température + humidité dth11
-carte relais 4modules
-Ecran 20*4

Petit système qui m'as couté 40€ max au lieux de je ne sais combien dans le commerce. Sans parler que je ne compte pas m'arrêter la. J'ai deja une idée de photo prise chaque jours avec affichage sur un petit écran en dehors de la box mais ça c'est mon petit coté geeks qui ressort :blush:

Bref tout ce pour dire que j'ai réussi jusqu'à présent à débrouiller via divers sources, à faire un petit bout de programme. N'étant pas expert mon programme est un peu brouillon je pense.
Alors si quelques personnes pouvait me rendre le service de m'indiquer deux trois choses à corriger voir plus si jamais mon programme vraiment très brouillon :o :p.

#include <Wire.h>
#include "DHT.h"
#include "ds3231.h"
#include "rtc_ds3231.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#define BUFF_MAX 128
#define RELAY_1 2
#define RELAY_2 3
#define RELAY_3 4
#define DHTPIN 5
#define DHTTYPE DHT11   // DHT 11
int hext = 22;
int hall = 10;
int tempj = 21;
int tempn = 15;
uint8_t time[8];
char recv[BUFF_MAX];
unsigned int recv_size = 0;
unsigned long prev, interval = 5000;
DHT dht(DHTPIN, DHTTYPE);

void setup()
{
    Serial.begin(9600);
    Wire.begin();
    DS3231_init(DS3231_INTCN);
    memset(recv, 0, BUFF_MAX);
    Serial.println("GET time");
    lcd.init();
    // Print a message to the LCD.
    lcd.backlight();
    lcd.setCursor(3,0);
    lcd.print("Box de Culture");
    lcd.setCursor(15,3);
    lcd.print(hall);
    lcd.print("/");
    lcd.print(hext);
    pinMode(RELAY_1, OUTPUT);  
    digitalWrite(RELAY_1, HIGH);
    pinMode(RELAY_2, OUTPUT);  
    digitalWrite(RELAY_2, HIGH);
    dht.begin();
}

void loop()
{
  float t2 = dht.readTemperature();
    char in;
    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // show time once in a while
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t);

        // there is a compile time option in the library to include unixtime support
#ifdef CONFIG_UNIXTIME
        snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d %ld", t.year,
             t.mon, t.mday, t.hour, t.min, t.sec, t.unixtime);
#else
        snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d", t.year,
             t.mon, t.mday, t.hour, t.min, t.sec);
#endif

        
    }

  lcd.setCursor(0,3);
    lcd.print(t.hour);
    lcd.print(":");
    lcd.print(t.min);
  lcd.setCursor(6,3);
    lcd.print(t2);
    lcd.print("*C");
    if(t.hour >= hall && t.hour < hext) 
    {
      lcd.setCursor(0,1);
      lcd.print("Eclairage : Allumee");
      digitalWrite(RELAY_1, LOW);
      if(t.min > 15 && t.min < 30 || t.min > 45 && t.min <60) // interval activation de la ventilation (jour)
        {
        lcd.setCursor(0,2);
        lcd.print("Ventilation : Allumee");
        digitalWrite(RELAY_2, LOW);
        }
       else
       {
        lcd.setCursor(0,2);
        lcd.print("Ventilation : Eteinte");
        digitalWrite(RELAY_2, HIGH);
       }
      if(t2 < tempj)   //Temperature minimal avant declanchement chauffage (jour)
      {
        digitalWrite(RELAY_3, LOW);
      }
      else
      {
        digitalWrite(RELAY_3, HIGH);
      }
    }
    else
   {
      lcd.setCursor(0,1);
      lcd.print("Eclairage : Eteint");
      digitalWrite(RELAY_1, HIGH);
       if(t.min > 15 && t.min < 30 )   //interval activation de la ventilation (nuit)
       {
       lcd.setCursor(0,2);
        lcd.print("Ventilation : Allumee");
        digitalWrite(RELAY_2, LOW);
        }
       else
       {
        lcd.setCursor(0,2);
        lcd.print("Ventilation : Eteinte");
        digitalWrite(RELAY_2, HIGH);
       }

      if(t2 < tempn) //temperature minimal avant declanchement chauffage(nuit)
      {
        digitalWrite(RELAY_3, LOW);
      }
      else
      {
        digitalWrite(RELAY_3, HIGH);
      }
   }



 
    if (Serial.available() > 0) {
        in = Serial.read();

        if ((in == 10 || in == 13) && (recv_size > 0)) {
            parse_cmd(recv, recv_size);
            recv_size = 0;
            recv[0] = 0;
        } else if (in < 48 || in > 122) {;       // ignore ~[0-9A-Za-z]
        } else if (recv_size > BUFF_MAX - 2) {   // drop lines that are too long
            // drop
            recv_size = 0;
            recv[0] = 0;
        } else if (recv_size < BUFF_MAX - 2) {
            recv[recv_size] = in;
            recv[recv_size + 1] = 0;
            recv_size += 1;
        }

    }
     delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t2) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t2, h, false);

  //Serial.print("Humidity: ");
  //Serial.print(h);
  //Serial.print(" %\t");
  //Serial.print("Temperature: ");
  //Serial.print(t2);
  //Serial.print(" *C ");
  //Serial.print(f);
  //Serial.print(" *F\t");
  //Serial.print("Heat index: ");
  //Serial.print(hic);
  //Serial.print(" *C ");
  //Serial.print(hif);
  //Serial.println(" *F");
    
}

void parse_cmd(char *cmd, int cmdsize)
{
    uint8_t i;
    uint8_t reg_val;
    char buff[BUFF_MAX];
    struct ts t;

    //snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);
    //Serial.print(buff);

    // TssmmhhWDDMMYYYY aka set time
    if (cmd[0] == 84 && cmdsize == 16) {
        //T355720619112011
        t.sec = inp2toi(cmd, 1);
        t.min = inp2toi(cmd, 3);
        t.hour = inp2toi(cmd, 5);
        t.wday = cmd[7] - 48;
        t.mday = inp2toi(cmd, 8);
        t.mon = inp2toi(cmd, 10);
        t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
        DS3231_set(t);
        Serial.println("OK");
    } else if (cmd[0] == 49 && cmdsize == 1) {  // "1" get alarm 1
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 50 && cmdsize == 1) {  // "2" get alarm 1
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 51 && cmdsize == 1) {  // "3" get aging register
        Serial.print("aging reg is ");
        Serial.println(DS3231_get_aging(), DEC);
    } else if (cmd[0] == 65 && cmdsize == 9) {  // "A" set alarm 1
        DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
        //ASSMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd
        }
        uint8_t flags[5] = { 0, 0, 0, 0, 0 };
        DS3231_set_a1(time[0], time[1], time[2], time[3], flags);
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 66 && cmdsize == 7) {  // "B" Set Alarm 2
        DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
        //BMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd
        }
        uint8_t flags[5] = { 0, 0, 0, 0 };
        DS3231_set_a2(time[0], time[1], time[2], flags);
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register
        Serial.print("temperature reg is ");
        Serial.println(DS3231_get_treg(), DEC);
    } else if (cmd[0] == 68 && cmdsize == 1) {  // "D" - reset status register alarm flags
        reg_val = DS3231_get_sreg();
        reg_val &= B11111100;
        DS3231_set_sreg(reg_val);
    } else if (cmd[0] == 70 && cmdsize == 1) {  // "F" - custom fct
        reg_val = DS3231_get_addr(0x5);
        Serial.print("orig ");
        Serial.print(reg_val,DEC);
        Serial.print("month is ");
        Serial.println(bcdtodec(reg_val & 0x1F),DEC);
    } else if (cmd[0] == 71 && cmdsize == 1) {  // "G" - set aging status register
        DS3231_set_aging(0);
    } else if (cmd[0] == 83 && cmdsize == 1) {  // "S" - get status register
        Serial.print("status reg is ");
        Serial.println(DS3231_get_sreg(), DEC);
    } else {
        Serial.print("unknown command prefix ");
        Serial.println(cmd[0]);
        Serial.println(cmd[0], DEC);
    }
}

Merci d'avance à tous. Si certains sont intéressé par des photo pas de problèmes ! :stuck_out_tongue:

bonjour,
je dirai siplement, qu'à partir du moment ou ca tombe en marche, le brouillon on s'en tape :slight_smile:
de toute facon ca compile, donc pas d'erreur.

après, j'ai pas trop regardé, il y a peut être des fonctions répétitives que tu pourrais regrouper en une seule fonction.

Oui ca fonctionne mais je cherche une petite optimisation, afin de ne pas faire de processus inutile qui pourraient ralentir voir faire buguer le tout un jour. je pense qu'il est préférable d'optimiser un peu plusieurs fois qu'une bonne fois pour toute sur un pavé de 3000 lignes après je cherche aussi de mon coté j'ai par exemple envoyé les textes comme Eclairage, Ventilention etc.. dans le void setup.

je pense qu'il est préférable d'optimiser un peu plusieurs fois qu'une bonne fois pour toute sur un pavé de 3000 lignes

Sage pensée.

Je ne suis pas un pro de la prog mais je te propose quelques idées par forcément essentielles.

  • Retirer les lignes de code et de commentaires inutiles comme:
// Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);

Franchement qu'est-ce que tu as à fiche des Farenheits,
C'est inutile, ça gâche bêtement des octets (les fonctions) et ça complique la lecture (les commentaires).
Par contre n'hésite pas à ajouter tes propres commentaires là où tu as du relire plusieurs fois pour comprendre.

  • Pour bien s'approprier le code je conseille, (tout le monde n'est d'accord en particulier les jeunes), de traduire les commentaires en français. Certains sont évidents et peuvent être laissés dans la langue originale mais souvent en lisant on croit comprendre et en traduisant on se rend compte que ce n'est pas si évident que cela.

  • Eviter des fonctions qui tiennent sur trop de pages de code.
    Il faut rester raisonnable et ne pas abuser car le fait de déclarer une fonction utilise quelques octets mais il me semble que la fonction loop() pourrait être scindée.
    La mise au point s'en trouve facilité.

à partir du moment ou ca tombe en marche, le brouillon on s'en tape

Pour moi l'expression "tomber en marche" est péjorative : si on comprend pas pourquoi cela fonctionne , on sera incapable de comprendre pourquoi tout d'un coup cela ne fonctionne plus.

Je ne suis pas un pro de la prog mais je te propose quelques idées par forcément essentielles.

elles ne sont pas prises en compte dans la compilation 68tjs :wink:

Pour moi l'expression "tomber en marche" est péjorative : si on comprend pas pourquoi cela fonctionne , on sera incapable de comprendre pourquoi tout d'un coup cela ne fonctionne plus.

c'est une expression que l'on utilise souvent, Artouste, Icare, JF et d'autres :slight_smile:
parfois on ne sait pas pourquoi, c'est certain, mais souvent on le sait en utilisant des moyens détournés et non académiques.

pour le reste, les farenheit, c'est sur que ca ne "serre" pas à grand chose pour une box culture frenchie.

elles ne sont pas prises en compte dans la compilation

Les lignes de commentaires bien sûr mais les fonctions qui sont appelées dans le code comme la farenheit, bien sûr que si elle sont prise à la compilation

Je ne veux pas polémiquer mais je crois que "tomber en marche" c'est moi qui l'ait importé. Elle n'est pas de moi mais d'un ancien collègue de boulot. On l'employait contre d'autres collègues avec qui il fallait toujours re-vérifier leur travaux. Le sens qu'on lui donnait a toujours été péjoratif. J'ai constaté qu'elle a été adopté ici comme j'ai apprécié et adopté l'expression d'Artouste "totalement inutile donc indispensable".

Comme dit plus haut si ça marche.....
Maintenant, il est toujours possible de perfectionner.
Personnellement, pour la lisibilité et la facilité de maintenance j'essaye de ne pas mettre de code dans loop() seulement des appels de fonctions.
Dans ton cas tu pourrais avoir

void loop(void){
     gestion_temperature();
     gestion_eclairage();
     gestion_chauffage();
     gestion_ventilation();
     affichage();
}

Cela permet d'avoir une vue très synthétique du déroulement du programme.
Chaque fonction traite une fonction particulière. Cela évite des petit morceaux de code dispersés un peu partout. Comme ça, si demain tu changes de capteur de température ou d'écran tu ne casses pas tout ton programme mais seulement une fonction.
Et pas de delay() dans le code, c'est une source de problème car cela bloque l'exécution du programme.

Les lignes de commentaires bien sûr mais les fonctions qui sont appelées dans le code comme la farenheit, bien sûr que si elle sont prise à la compilation

je n'ai pas dit le contraire, relis ma réponse, même si je me suis trompé de ligne dans le quote ;).
- Retirer les lignes de code et de commentaires inutiles comme:
elles ne sont pas prises en compte dans la compilation 68tjs

pour le reste, les farenheit, c'est sur que ca ne "serre" pas à grand chose pour une box culture frenchie.

Je dois mal m'exprimer mais c'est ce que j'ai pensé quand j'ai écrit.
Bon on va passer a autre chose l'important est d'avoir fait passer le message.