Door programming problem in automatic operation

Hello, I am currently carrying out a 8 week internship assignment where I have to automate a door for a solar-powered chicken coop, and I'm already in my 7th week.

I am currently using an Arduino UNO board, a 2 channel relay module, a solar cell, a 3.7V lipo battery and a LCD display with buttons.

The door is opened and closed using a motor that turns in either direction and rolls or unwinds a wire that opens or closes the door.

I first managed to carry out a loop test program where by pressing the RIGHT button on the LCD screen: the door closes up to the DOWN sensor, stops for 3 seconds when the motor is paused, then goes up until it reaches the UP sensor, where the motor pauses again before closing the loop. Just press the RIGHT button again to restart the loop.

Here is the assembly I made:

The program I created before also makes it possible to display on the LCD screen the voltage consumed by the motor and the voltage at the terminals of the solar cell.

Now I want to create a new program based on the manual version, and where the door will open and close according to the brightness threshold measured by the solar cell. Morning and evening time delays will also be integrated, where the door will open in the morning, and close in the evening. The manual door operation program with the test loop will still be present in the program since it is an improvement of the old program.

In theory, once the assembly is powered by the lipo battery, the program will have 3 alternatives:

-If the voltage across the solar cell is below 0 for at least 10 seconds, and as long as the RIGHT button is not pressed, the automatic closing program will be triggered and the door will close.

-If the voltage across the solar cell is greater than or equal to 0 for at least 10 seconds, and as long as the RIGHT button is not pressed, the automatic opening program will be triggered and the door will open.

-If the RIGHT button is triggered within 10 seconds after the battery has supplied power to the fixture, the manual closing and opening program will be triggered and the door will close and then open.

Here is the program that I realized so far:

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield
 
#include <LiquidCrystal.h>
 
// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT  = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define CapteurBAS 11
#define CapteurHAUT 12
#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2

int state_relais_manuel = 0;
int state_fermeture_auto = 0;
int state_ouverture_auto = 0;
int state_seuil_ensoleillement;

unsigned long temps_mesures = 0;
unsigned long temps_relais_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;


void setup() 
{
    // On met les pin de chaque relais en sortie
    pinMode(RelayPin1, OUTPUT);
    pinMode(RelayPin2, OUTPUT);

    pinMode(CapteurBAS, INPUT);
    pinMode(CapteurHAUT, INPUT);

    lcd.begin(16, 2);              // Démarrage de l'écran
    lcd.setCursor(0,0);            // Positionnement du curseur au début
    lcd.print("Mesure tension"); // Message
    
}

void loop() 
{
    lcd_key = read_LCD_buttons();  // Lecture des touches 
    // Sous traite les diff√©rentes t√Ęches
    task_mesure_tensions();
    task_relais_manuel();

    switch (lcd_key)               // Action en cas de touche pressée
   {
     case btnRIGHT: //en appuyant sur le bouton RIGHT
       {
        if (state_relais_manuel == 0){
          state_relais_manuel = 1; //on incrémente la variable state de 1
        } 
        break;
       }
   }

    if (state_seuil_ensoleillement = 0){
          task_fermeture_auto(); //lance le programme de fermeture dans la nuit
          state_fermeture_auto++; //incrémente de 1a la valeur de la variable
        }

    else if (state_seuil_ensoleillement = 1){
          task_ouverture_auto(); //lance le programme d'ouverture dans la journée
          state_ouverture_auto++; //incrémente de 1a la valeur de la variable
        }
}//boucle

void task_mesure_tensions() 
{        
    unsigned long temps_actuel = millis();

    if( (temps_actuel - temps_mesures) >= 250ul )
    {
        temps_mesures = temps_actuel;

        // Transforme la mesure (nombre entier) en tension via un produit en croix
        int valeur1 = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
        int valeur2 = analogRead(A2); // Mesure la tension consommée par le moteur

        float tension1 = (float)valeur1 * (5.0 / 1023.0);   
        float tension2 = (float)valeur2 * (5.0 / 1023.0); 
        
        // Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
        lcd.setCursor(0,1);            // Positionnement du curseur début de ligne 

        if (tension1 < 1){
          state_seuil_ensoleillement = 0;//la variable passe à 0 lorsqu'il fait nuit
        }
        else if (tension1 >= 1){
          state_seuil_ensoleillement = 1;//la variable passe à 1 lorsqu'il fait jour
        } 

        lcd.print("L");
        lcd.print(state_seuil_ensoleillement); //affiche la valeur de l'état de la cellule solaire

        lcd.print(" O");
        lcd.print(state_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique
        
        lcd.print(" F");
        lcd.print(state_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique

        lcd.print(" M");
        lcd.print(state_relais_manuel); //affiche la valeur de l'état du mode manuel de la porte

              
    }//if    

}//task_mesure_tensions

void task_relais_manuel() 
{  
    unsigned long temps_actuel = millis();

    switch( state_relais_manuel )
    {
        case    1:
            // On allume l'un des relais alors que l'autre est éteint...
            digitalWrite(RelayPin1, LOW);
            digitalWrite(RelayPin2, HIGH);
            //delay(10000);
            temps_relais_manuel = temps_actuel;
            state_relais_manuel++;
        
        break;    

        case    2:
            if( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
            {
                // On éteint ensuite le ler relais: le moteur est en pause pendant 3 secondes...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);
                //delay(5000);
                temps_relais_manuel = temps_actuel;
                state_relais_manuel++;
                
            }//if
            
        break;

        case    3:
            if( (temps_actuel - temps_relais_manuel) >= 3000ul )
            {
                // Puis on allume l'autre...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, LOW);
                //delay(10000);
                temps_relais_manuel = temps_actuel;
                state_relais_manuel++;
                
            }//if
            
        break;

        case    4:
            if( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
            {
                // Enfin, on éteins le 2ème relais: le moteur est encore en pause pendant 3 secondes...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);
                //delay(5000);
                temps_relais_manuel = temps_actuel;
                state_relais_manuel++;
                
            }//if
        
        break;

        case    5:
            if( (temps_actuel - temps_relais_manuel) >= 3000ul )
            {
                //reviens à l'état initial après 3 secondes de pause
                state_relais_manuel = 0;
                
            }//if        
            
        break;                
        
    }//switch
    
}//task_relais_manuel

void task_fermeture_auto () 
{  
    unsigned long temps_actuel = millis();

    switch( state_fermeture_auto )
    {
        case    1:
            if( (temps_actuel - temps_fermeture_auto) >= 10000ul && state_relais_manuel == 0 && state_ouverture_auto == 0 )
            {
              // Une fois la tempo écoulée, on active l'un des relais alors que l'autre reste inactif...
              digitalWrite(RelayPin1, LOW);
              digitalWrite(RelayPin2, HIGH);
              //delay(10000);
              temps_fermeture_auto = temps_actuel;
              state_fermeture_auto++;
            }//if
        
        break;    

        case    2:
            if( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
            {
                // On éteint ensuite le ler relais: la porte est complétement fermée
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);
                //delay(5000);
                temps_fermeture_auto = temps_actuel;
                state_fermeture_auto++;
                
            }//if
            
        break;

        case    3:
            if( (temps_actuel - temps_fermeture_auto) >= 3000ul )
            {
                //laisse la porte fermée et remet la variable à l'état initial.
                state_fermeture_auto = 0;               
            }//if       
            
        break;                
        
    }//switch
    
}//task_fermeture_auto

void task_ouverture_auto () 
{  
    unsigned long temps_actuel = millis();

    switch( state_ouverture_auto )
    {
        case    1:
            if( (temps_actuel - temps_ouverture_auto) >= 10000ul && state_relais_manuel == 0 && state_fermeture_auto == 0)
            {
              // Une fois la tempo écoulée, on active le 2ème relais alors que le 1er reste inactif...
              digitalWrite(RelayPin1, HIGH);
              digitalWrite(RelayPin2, LOW);
              //delay(10000);
              temps_ouverture_auto = temps_actuel;
              state_ouverture_auto++;
            }//if
        
        break;    

        case    2:
            if( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
            {
                // On éteint ensuite le ler relais: le moteur est en pause pendant 3 secondes...
                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);
                //delay(5000);
                temps_ouverture_auto = temps_actuel;
                state_ouverture_auto++;
                
            }//if
            
        break;

        case    3:
            if( (temps_actuel - temps_ouverture_auto) >= 3000ul )
            {
                //laisse la porte ouverte et remet la variable à l'état initial.
                state_ouverture_auto = 0;               
            }//if       
            
        break;                
        
    }//switch
    
}//task_ouverture_auto

// Fonction de lecture des touches
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);   // Lecture du port analogique
 
 // Les valeurs qui suivent doivent être adaptées au shield
 if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
 if (adc_key_in < 50)   return btnRIGHT;     // 0
 if (adc_key_in < 195)  return btnUP;        // 99
 if (adc_key_in < 380)  return btnDOWN;      // 255
 if (adc_key_in < 555)  return btnLEFT;      // 409
 if (adc_key_in < 790)  return btnSELECT;    // 640
 
 return btnNONE;
}

To perform tests, I set the door halfway up, then started a self-closing test by plunging my workroom into darkness.

Result: Strangely, after 10 seconds the door opens instead of closing, and stops at the UP sensor.

This time I repeat the experiment, now illuminating the solar cell in daylight.

Result: This time the door still opens, but without stopping at the UP sensor.

To find my error, I decide to modify my program so that the LCD screen displays, instead of the voltages at the terminals of the solar cell and the motor, the values of the variables "state_fermeture_auto" for F, "state_ouverture_auto" for O, and ‚Äústate_relais_manuel‚ÄĚ for M. L makes it possible to designate the value of ‚Äústate_seuil_ensolenement‚ÄĚ.

I then reproduce the automatic closing test.

Result: First, for some reason, the screen displays anything for "auto_opening_state", with fluctuating multi-digit numbers that change each time instead of just showing a single digit like L, F, and M.

In addition, after 10 seconds spent in the dark, the door opens while the value of "auto_fermeture_state" remains at 0, and does not even stop when it comes near the sensor.

Another remark: by varying the value of "state_seuil_ensolenement", called L, during the 10 seconds, alternately from 0 to 1 before returning to 0, the door opens once the 10-second period has passed.

Indeed, the extinguished program supposed to close while L was assigned to 0 DURING these entire 10 seconds.

Out of curiosity, I decided to try the manual mode of the program by pressing the RIGHT button.

Result: The loop operates without interruption, and the value M varies well according to the states of the relays.

So only the manual mode function of the door works, but I don't understand the mistakes I made for the automatic opening and closing functions.

Have I made a programming error?

Thank you in advance if someone could answer me quickly and suggest a correction to my program.

1 Like

Started looking, stopped here:

 if (state_seuil_ensoleillement = 0)

Same thing a few lines down too.

Nice clear images +1

a single equal sign means assign a value
in most cases you want a comparison
which means coding a double equalsign "==" instead of a single equal sign "="

 if (state_seuil_ensoleillement == 0)

best regards Stefan

Thank you. I just corrected the detail, but I still have problems.

I then performed an automatic closing test.

Result: Strangely, the value of F now displays anything, and I am unable to read its value on the screen.

I also observe, when trying to modify the display program, that it is F that is bugging instead of O.

Instead, I decide to perform an automatic opening test:

Result: Strangely, I also have a display problem at the level of O

Here is a photo, where the numbers change all the time for no reason:

I then decide to display the values ‚Äč‚Äčwithout displaying the corresponding letters.

Result: Still display problems.

However, I still decide to perform an automatic shutdown test.

Result: After 10 seconds in the dark, the door finally closes and stops at the BAS sensor.

I then perform an automatic opening test by lighting the solar cell in daylight.

Result: Strangely, after 10 seconds the door does not even open. And even if you put the solar cell back in the dark for 10 seconds, it doesn't open.

Can you help me solve this problem please? I need to know the states of the variables.

debugging will become much faster if you use the serial monitor to display values.
The advantage of the serial-monitor is that you can write a lot of letters in a single line and that you can write as many lines as you want after each other.
For developping programs using the serial monitor is the standard-thing to do.

And you can use something that is called "macro" to reduce the amount of keystrokes you have tp type into your code by using a macro.

From the pictures I conclude that you are using an arduino or Arduino-clone like a seeeduino or something similar.

So here I insert a demo-code that demonstrates the use of this "serial debug-output-macro"

You can use this macro for debugging but it is not limited to that.

You might have questions about how to add this debug-macro into your code
if you have just ask here in the forum.
This democode has three useful functions
show filename of compiled file in the serial-monitor
a non-blocking timer-function
and a "heartBeatBlinker" that indicates your loop is running.

But first upload the demo-code and watch the serial monitor.

void PrintFileNameDateTime()
{
  Serial.println("Code running comes from file ");
  Serial.println(__FILE__);
  Serial.print("  compiled ");
  Serial.print(__DATE__);
  Serial.print(" ");
  Serial.println(__TIME__);  
}


boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();  
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

unsigned long MyTestTimer = 0;                   // variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);
  
  if ( TimePeriodIsOver(MyBlinkTimer,BlinkPeriod) ) {
    digitalWrite(IO_Pin,!digitalRead(IO_Pin) ); 
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
}

//#define debugTxtVar(abc, def) Serial.print("<  "#abc" = "); Serial.print(def); Serial.println('>')

// using the #define "statement" to make the compiler "write" code
// #define can be used to make the compiler replace text that describes something with (almost) anything else
// easy example 
// let's assume IO-pin number 4 shall be set to work as output 
// the command for defining an IO-pin to be configured as output is
//
// pinMode(4,OUTPUT); 
// the number "4" says nothing about he purpose of this IO-pin

// let's assume the IO-pin shall switch On/Off a buzzer

// you would have to add a comment to explain
// pinMode(4,OUTPUT); // IO-pin 4 is buzzer

// the compiler needs the number. To make the code easier to read and understand
// #define BuzzerPin 4
// So the command looks like this
// pinMode(BuzzerPin,OUTPUT);

// the descriptive word "BuzzerPin" gets replaced through the compiler by a "4"
// so what the compiler compiles is still 'pinMode(4,OUTPUT);'

// the #define can do much more than just replace a word by a single number
// it can even take parameters like in this example

#define debugTxtVar(myParameterText, variableName) \
        Serial.print(#myParameterText " " #variableName"="); \
        Serial.println(variableName); 
        
int myVar = 1234;
int mySecondVar = 999;

void loop() {
  BlinkHeartBeatLED(OnBoard_LED,250);

  if ( TimePeriodIsOver(MyTestTimer,1000) ) {
    debugTxtVar("first line " , myVar);
    mySecondVar++;
    debugTxtVar("second line" , mySecondVar);
  }  
}

I took a look into your code.
The code is hard to read because you are using non-selfexplainable names and numbers

example

                digitalWrite(RelayPin1, HIGH);
                digitalWrite(RelayPin2, HIGH);

RelayPin1 and 2 switch something on / off What is it what gets switched on/off?

a ventilator, a lamp?, an egg-boiler? No idea from the word RelayPin1

The name should be selfexplaining.

you use a switch-case-statement

    switch( state_relais_manuel )
    {
        case    1:
            // On allume l'un des relais alors que l'autre est éteint...

the number itself says nothing.
Your comment says nothing too. Switch one relay on the other off

What does happen if you have done

            digitalWrite(RelayPin1, LOW);
            digitalWrite(RelayPin2, HIGH);

is the swimming-pool-heating switched on or your feather-shaving-propeller switched off?

I'm using nonsense-examples to emphasise on the non-explaining-character of your symbols.

This makes it hard to understand what your code does. Especcially for other who try to help you and for the person who will judge about your project.

I offer you to help under the pre-condition of changing all names to a self-explaining style. Rewriting your code in this way will take less time than explaining what Relay1Pin1 etc. etc. etc. means. Especcially if you add the time it needs until you receive answers.

It is up to you if you want to go in encrypting your code on your own
or

getting cooperative by renaming each and every symbol in a selfdescriptive style.

If you have questions about how to do the renaming just ask.

best regards Stefan

1 Like

Hi. Honestly, I don't want to change the names of my variables to avoid being overwhelmed.

Otherwise, for your information, the relays allow you to control the direction of rotation of a motor (direct current brush) which allows, depending on its power supply, to open or close the door by winding or unwinding a wire hooked to the guillotine type door.

By the way, I modified my program adding more comments, hoping to help you understand

Indeed, I want for the automatic closing test the value of L to be 0 for at least 10 seconds (with the help of the millis () function), otherwise the door will not close.
I have to find an online program with actions that take place if their variables related to their conditions have been fulfilled for some time without interruption.
I then decide to embed while loops in the automatic closing and opening functions, where I make sure that as long as the 10 seconds delay has not elapsed, if the value of L changes, the value F or O returns to 0 depending on the function and the 10-second delay is reset to 0.

This is what I modified

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield
 
#include <LiquidCrystal.h>
 
// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT  = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
#define CapteurBAS 11 //le port numérique D11 est connecté au capteur BAS
#define CapteurHAUT 12 //le port numérique D12 est connecté au capteur HAUT

int state_relais_manuel = 0;
int state_fermeture_auto = 0;
int state_ouverture_auto = 0;
int state_seuil_ensoleillement;

unsigned long temps_mesures = 0;
unsigned long temps_relais_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;


void setup() 
{
    // On met les pin de chaque relais en sortie
    pinMode(RelayPin1, OUTPUT);
    pinMode(RelayPin2, OUTPUT);

    pinMode(CapteurBAS, INPUT);
    pinMode(CapteurHAUT, INPUT);

    lcd.begin(16, 2);              // Démarrage de l'écran
    lcd.setCursor(0,0);            // Positionnement du curseur au début
    lcd.print("Mesure tension"); // Message
    
}

void loop() 
{
    lcd_key = read_LCD_buttons();  // Lecture des touches 
    // Sous traite les diff√©rentes t√Ęches
    task_mesure_tensions();
    task_relais_manuel();

    switch (lcd_key)               // Action en cas de touche pressée
   {
     case btnRIGHT: //en appuyant sur le bouton RIGHT
       {
        if (state_relais_manuel == 0){
          state_relais_manuel = 1; //on incrémente la variable state de 1
        } 
        break;
       }
   }

    if (state_seuil_ensoleillement == 0){
          task_fermeture_auto(); //lance le programme de fermeture dans la nuit
          state_fermeture_auto++; //incrémente de 1a la valeur de la variable
        }

    else if (state_seuil_ensoleillement == 1){
          task_ouverture_auto(); //lance le programme d'ouverture dans la journée
          state_ouverture_auto++; //incrémente de 1a la valeur de la variable
        }
}//boucle

void task_mesure_tensions() //permet de prendre des mesures de tensions et d'afficher des données sur l'écran LCD
{        
    unsigned long temps_actuel = millis();

    if( (temps_actuel - temps_mesures) >= 250ul )
    {
        temps_mesures = temps_actuel;

        // Transforme la mesure (nombre entier) en tension via un produit en croix
        int valeur1 = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
        int valeur2 = analogRead(A2); // Mesure la tension consommée par le moteur

        float tension1 = (float)valeur1 * (5.0 / 1023.0);   
        float tension2 = (float)valeur2 * (5.0 / 1023.0); 
        
        // Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
        lcd.setCursor(0,1);            // Positionnement du curseur début de ligne 

        if (tension1 < 1){
          state_seuil_ensoleillement = 0;//la variable passe à 0 lorsqu'il fait nuit
        }
        else if (tension1 >= 1){
          state_seuil_ensoleillement = 1;//la variable passe à 1 lorsqu'il fait jour
        } 

        lcd.print("L");
        lcd.print(state_seuil_ensoleillement); //affiche la valeur de l'état de la cellule solaire
        
        lcd.print(" F");
        lcd.print(state_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique
        
        lcd.print(" O");
        lcd.print(state_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique

        lcd.print(" M");
        lcd.print(state_relais_manuel); //affiche la valeur de l'état du mode manuel de la porte

              
    }//if    

}//task_mesure_tensions

void task_relais_manuel() //permet d'activer le test de fonctionnement manuel de la porte
{  
    unsigned long temps_actuel = millis();

    switch( state_relais_manuel )
    {
        case    1:
            // Après l'appui du bouton, le moteur tourne dans un sens et la porte commence à se fermer...
            digitalWrite(RelayPin1, LOW); //le relais 1 est actif
            digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
            temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
            state_relais_manuel++; //on incrémente la valeur de la variable de 1
        
        break;    

        case    2:
            if( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
            {
                //...le moteur se met en pause et la porte s'arrête pendant 3 secondes...
                digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
                digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
                temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
                state_relais_manuel++; //on incrémente la valeur de la variable de 1
                
            }//if
            
        break;

        case    3:
            if( (temps_actuel - temps_relais_manuel) >= 3000ul )
            {
                //une fois la pause finie, le moteur tourne dans l'autre sens et la porte commence à s'ouvrir...
                digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
                digitalWrite(RelayPin2, LOW); //le relais 2 est actif
                temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
                state_relais_manuel++; //on incrémente la valeur de la variable de 1
                
            }//if
            
        break;

        case    4:
            if( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
            {
                // ...le moteur se met en pause et la porte s'arrête pendant 3 secondes
                digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
                digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
                temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
                state_relais_manuel++; //on incrémente la valeur de la variable de 1
                
            }//if
        
        break;

        case    5:
            if( (temps_actuel - temps_relais_manuel) >= 3000ul )
            {
                //reviens à l'état initial après 3 secondes de pause
                state_relais_manuel = 0; //la variable repasse à 0 
                
            }//if        
            
        break;                
        
    }//switch
    
}//task_relais_manuel

void task_fermeture_auto () //permet d'activer la fermeture automatique de la porte avec le seuil de luminosité
{  
    unsigned long temps_actuel = millis();

    switch( state_fermeture_auto )
    {
        case    1:
            while( (temps_actuel - temps_fermeture_auto) < 10000ul)  
            {//tant que les 10 secondes ne se soient pas découlées...
              if (state_relais_manuel == 1 || state_ouverture_auto == 1)
              {//on vérifie s'il fait toujours nuit ou si on active le mode manuel de la porte
                state_fermeture_auto = 0; //la variable repasse à 0 
                temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
              }
            }  

            if (state_relais_manuel == 0 || state_ouverture_auto == 0 ||(temps_actuel - temps_fermeture_auto) >= 10000ul )
              {// Une fois les 10 secondes découlées, le moteur tourne dans un sens et la porte commence à se fermer
              digitalWrite(RelayPin1, LOW); //le relais 1 est actif
              digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
              temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
              state_fermeture_auto++; //on incrémente la valeur de la variable de 1
              }//if
        
        break;    

        case    2:
            if( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
            {
                // le moteur se met en pause et la porte s'arrête.
                digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
                digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
                temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
                state_fermeture_auto++; //on incrémente la valeur de la variable de 1
                
            }//if
            
        break;

        case    3:
            if( (temps_actuel - temps_fermeture_auto) >= 3000ul )
            {
                //laisse la porte fermée et remet la variable à l'état initial.
                state_fermeture_auto = 0; //la variable repasse à 0                 
            }//if       
            
        break;                
        
    }//switch
    
}//task_fermeture_auto

void task_ouverture_auto () //permet d'activer l'ouverture automatique de la porte avec le seuil de luminosité
{  
    unsigned long temps_actuel = millis();

    switch( state_ouverture_auto )
    {
        case    1:
            while( (temps_actuel - temps_fermeture_auto) < 10000ul) 
            {//tant que les 10 secondes ne se soient pas découlées...
              if (state_relais_manuel == 1 || state_fermeture_auto == 1)
              {//on vérifie s'il fait toujours jour ou si on active le mode manuel de la porte
                state_ouverture_auto = 0; //la variable repasse à 0
                temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
              }
            }  

            if (state_relais_manuel == 0 || state_fermeture_auto == 0 ||(temps_actuel - temps_ouverture_auto) >= 10000ul )
              {// Une fois les 10 secondes découlées, le moteur tourne dans l'autre sens et la porte commence à s'ouvrir
              digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
              digitalWrite(RelayPin2, LOW); //le relais 2 est actif
              temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
              state_ouverture_auto++; //on incrémente la valeur de la variable de 1
              }//if
        
        break;    

        case    2:
            if( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
            {
                // le moteur se met en pause et la porte s'arrête.
                digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
                digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
                temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
                state_ouverture_auto++; //on incrémente la valeur de la variable de 1
                
            }//if
            
        break;

        case    3:
            if( (temps_actuel - temps_ouverture_auto) >= 3000ul )
            {
                //laisse la porte ouverte et remet la variable à l'état initial.
                state_ouverture_auto = 0; //la variable repasse à 0               
            }//if       
            
        break;                
        
    }//switch
    
}//task_ouverture_auto

// Fonction de lecture des touches
int read_LCD_buttons() //permet de contr√īler les boutons de l'afficheur LCD
{
 adc_key_in = analogRead(0);   // Lecture du port analogique
 
 // Les valeurs qui suivent doivent être adaptées au shield
 if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
 if (adc_key_in < 50)   return btnRIGHT;     // 0
 if (adc_key_in < 195)  return btnUP;        // 99
 if (adc_key_in < 380)  return btnDOWN;      // 255
 if (adc_key_in < 555)  return btnLEFT;      // 409
 if (adc_key_in < 790)  return btnSELECT;    // 640
 
 return btnNONE;
}

Once the program has changed, I will again perform an automatic shutdown test.

Result: Strangely, no data is displayed when the LCD screen turns on.

Worse, once the 10 seconds have passed, whether in the daytime or in the dark, nothing happens. Even the manual mode no longer works when the RIGHT button is pressed.

Don't you have an idea of the source of my error please? Whether it is about the LCD display or the manual functions, auto open and auto close, which do not work?

Thank you in advance.

I'll echo the suggestion to change your variable names to something that helps understand their function. Whenever I do such a thing I let the compiler help me - change the declaration, copy it to the clipboard and recompile. It'll take you right to a line where you can paste the new name over the old. Rinse and repeat until you have a clean compile & move on to the next badly named thing.

When reading your (or any other) code, I'm trying to build a mental model of what it's doing. Names like Relay1 make it harder. If it gets hard enough, I'll just leave it to someone with more patience (if any).

Your switch on lcd_key is odd - since it only has one case, you might want to refactor it.

The FSM described in this thread is very similar to your project.  And it uses enums to describe states.

It may seem like a step backwards to add good names to things.  It's not.

I try to convince you to change variable names and give support on how to change your code to make it much more understandable even for yourself.

I started to analyse your code. let's say normal beginner-code.
Trying to add functionality at the place you are at programming or at a place what came to your mind first.

The state of the code now is pretty mixed up and hard to follow. Even for me as a hobbyprogrammer with 35 years of programming-experience.

And I'm pretty sure that is the real reason you want to keep your variable names: "please don't mix up my code even more."

NO ! Your code needs re-structuring to become easy to understand again. The current state of your code mixes functionality that should be well sorted to different functions.

You have come pretty far with your code but now it is messed up and I guess you have no idea how to re-structure it.

That's where the experience of all other users here chimes in.

If you divide the work of

"I have a problem code is not working as expected"

into smaller parts with more specific questions answer after answer will be posted and guide you through the process of re-structuring your code.

The first step to receive such guiding answers is to write down the steps your program shall do. It is VERY IMPORTANT to describe these steps WITHOUT programming-terms.
Write this description in NORMAL WORDS.

I will give you an example:

If the button for manual mode is pressed the following should happen:

Start Motor in that direction that will close the door
if sensor that detects "door in position closed" reports "door IS closed" then stop motor

wait for 3 seconds then

start motor in that direction that will open the door

if sensor that detects "door in position fully opened" reports "door IS fully opened" then stop motor

wait for 3 seconds then

finish manual mode

Same thing for automatic mode.

If you have given this description of what YOU want the program to do

the users here can give advice on how to re-structure your code. As this is done in small steps you will certainly be able to follow the changes and get used to the new structure of the code.

And I'm very sure you will enjoy the new clearness of this code.

best regards Stefan

So I enjoyed re-designing your code

you are using some timing-variables inside functions. This means without using the attribut static the space in RAM gets deleted each time the function is left.

For avoiding this the variables need to be either global or need the attribute "static"

A state-machine should just do some states but not more.
The state-machine needs an initial start to run through
this initial start can be coded with a "self-locking variabe-change" This technique can be used for stateCHANGE-detection.

there is an if-condition
f.e.

if (! itIsDay) {
  itIsDay = true;
}

This assures that changing the variable is only done once. Because after the first change the upper-if-condition is no longer true.

For finsihing s state-machine-sequence you can use the state of your sensors that sense "door opened" / "door closed"

as soon as the sensor reports door is in position you can stop
calling the state-machine

I put the digitalWrites of the relays into its own functions
This makes the code more readable. At both places:
1 the definition of the function because the function has a self-descriptive name

  1. at each place where the function gets called because the function has a self-descriptive name

  2. whenever you need to do a change to the code you make the change at one single place and can be sure you changed all places. Because all other places just call the function.

So I'm curious if you understand this version of your code that has the same functionality as yours but is much better readable.

Maybe you want to add some timeout-functions for opening/closing the door. The motor should not run for hours if a sensor has a broken wire and can't report "door opened" / "door closed"

There is a usual time how long it takes to open/close the door
if the expected signal is not seen after a certain time there is something wrong and you should stop the motor.

The code compiles but as I don't have your hardware I can't test it.

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield

#include <LiquidCrystal.h>

// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
#define CapteurBAS 11 //le port numérique D11 est connecté au capteur BAS
#define CapteurHAUT 12 //le port numérique D12 est connecté au capteur HAUT

int state_relais_manuel = 0;
int state_fermeture_auto = 0;
int state_ouverture_auto = 0;
int state_seuil_ensoleillement;

unsigned long temps_mesures = 0;
unsigned long temps_relais_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;

boolean itIsDay;   // c_est_le_jour;
boolean manualTestStarted = false;

const byte manuel_stateMachineIdle0 = 0;
const byte manuel_startClosingDoor1 = 1;
const byte manuel_waitForSensorDownClosed2 = 2;
const byte manuel_openDoorAfterWaiting3 = 3;
const byte manuel_waitForSensorDoorUp4 = 4;
const byte manuel_waitAndStopStateMachine5 = 5;

const byte autoclose_waitSomeTime1 = 1;
const byte autoclose_wait_SensorDownclosed2 = 2;
const byte autoclose_wait_someTime3 = 3;
const byte autoclose_idle0 = 0;

const byte autoOpen_waitSomeTime1 = 1;
const byte autoOpen_wait_SensorOpened2 = 2;
const byte autoOpen_wait_someTime3 = 3;
const byte autoOpen_idle0 = 0;


// Fonction de lecture des touches
int read_LCD_buttons() { //permet de contr√īler les boutons de l'afficheur LCD

  adc_key_in = analogRead(0);   // Lecture du port analogique

  // Les valeurs qui suivent doivent être adaptées au shield
  if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
  if (adc_key_in < 50)   return btnRIGHT;     // 0
  if (adc_key_in < 195)  return btnUP;        // 99
  if (adc_key_in < 380)  return btnDOWN;      // 255
  if (adc_key_in < 555)  return btnLEFT;      // 409
  if (adc_key_in < 790)  return btnSELECT;    // 640

  return btnNONE;
}

void setup() {
  // On met les pin de chaque relais en sortie
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);

  pinMode(CapteurBAS, INPUT);
  pinMode(CapteurHAUT, INPUT);

  lcd.begin(16, 2);            // Démarrage de l'écran
  lcd.setCursor(0, 0);         // Positionnement du curseur au début
  lcd.print("Mesure tension"); // Message
}

void printToLCD() {

  lcd.print("L");

  if (itIsDay) {
    lcd.print("jour"); //affiche la valeur de l'état de la cellule solaire
  }
  else {
    lcd.print("nuit"); //affiche la valeur de l'état de la cellule solaire
  }

  lcd.print(" F");
  lcd.print(state_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique

  lcd.print(" O");
  lcd.print(state_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique

  lcd.print(" M");
  lcd.print(state_relais_manuel); //affiche la valeur de l'état du mode manuel de la porte

} // printToLCD



void task_mesure_tensions() { //permet de prendre des mesures de tensions et d'afficher des données sur l'écran LCD
  // Transforme la mesure (nombre entier) en tension via un produit en croix
  int solarCellADC = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
  int motorADC     = analogRead(A2); // Mesure la tension consommée par le moteur

  float solarCellVoltage = (float)solarCellADC * (5.0 / 1023.0);
  float motorVoltage     = (float)motorADC     * (5.0 / 1023.0);

  // Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
  lcd.setCursor(0, 1);           // Positionnement du curseur début de ligne

  if (solarCellVoltage < 1.0) { // low solarCellVoltage means it is getting dark
    if (itIsDay) { // if this is a stateCHANGE day-to-night
      itIsDay = false; //la variable passe à false lorsqu'il fait nuit
      // start state-machine for closing the door
      state_fermeture_auto = autoclose_waitSomeTime1;
    }
    else  { // high solarCellVoltage means sunrising
      if (!itIsDay) { // if this is a stateCHANGE night-to-day
        itIsDay = true;  //la variable passe à true lorsqu'il fait jour
        // start state-machine for opening the door
        state_ouverture_auto = autoOpen_waitSomeTime1;
      }
    }
  }
}

void RunMotorClosing() {
  digitalWrite(RelayPin1, LOW); //le relais 1 est actif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void MotorStop() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void RunMotorOpening() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, LOW); //le relais 2 est actif
}


void task_relais_manuel() { //permet d'activer le test de fonctionnement manuel de la porte
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( state_relais_manuel )
  {
    case manuel_startClosingDoor1 :
      // Après l'appui du bouton, le moteur tourne dans un sens et la porte commence à se fermer...
      RunMotorClosing();
      temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
      state_relais_manuel = manuel_waitForSensorDownClosed2; // the names already explain what happends
      break;

    case manuel_waitForSensorDownClosed2 :
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { //...le moteur se met en pause et la porte s'arrête pendant 3 secondes...
        MotorStop();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_openDoorAfterWaiting3; // the names already explain what happends
      }
      break;

    case manuel_openDoorAfterWaiting3 :
      if ( (temps_actuel - temps_relais_manuel) >= 3000ul )
      { //une fois la pause finie, le moteur tourne dans l'autre sens et la porte commence à s'ouvrir...
        RunMotorOpening();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_waitForSensorDoorUp4; // the names already explain what happends
      }
      break;

    case manuel_waitForSensorDoorUp4 :
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // ...le moteur se met en pause et la porte s'arrête pendant 3 secondes
        MotorStop();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_waitAndStopStateMachine5; // the names already explain what happends
      }
      break;

    case manuel_waitAndStopStateMachine5 :
      if ( (temps_actuel - temps_relais_manuel) >= 3000ul )
      { //reviens à l'état initial après 3 secondes de pause
        state_relais_manuel = manuel_stateMachineIdle0; // the names already explain what happends
      }
      break;

    case manuel_stateMachineIdle0 :
      manualTestStarted = false; // manual cycle finished reset variable to false
      break;
  }//switch

}//task_relais_manuel



void task_fermeture_auto () { //permet d'activer la fermeture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( state_fermeture_auto )
  {
    case autoclose_waitSomeTime1 :
      if ( (temps_actuel - temps_fermeture_auto) < 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        //state_fermeture_auto = autoclose_checkBrightnes;
      }
      break;

    case autoclose_wait_SensorDownclosed2 :
      RunMotorClosing();
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        MotorStop();
        temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        state_fermeture_auto = autoclose_wait_someTime3; 
      }
      break;

    case autoclose_wait_someTime3 :
      if ( (temps_actuel - temps_fermeture_auto) >= 3000ul )
      { //laisse la porte fermée et remet la variable à l'état initial.
        state_fermeture_auto = autoclose_idle0;
      }
      break;

    case autoclose_idle0:
      // just do nothing
      break;
  } //switch

} //task_fermeture_auto



void task_ouverture_auto () { //permet d'activer l'ouverture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( state_ouverture_auto )
  {
    case autoOpen_waitSomeTime1 :
      if ( (temps_actuel - temps_fermeture_auto) < 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        state_ouverture_auto = autoOpen_wait_SensorOpened2;
      }
      break;

    case autoOpen_wait_SensorOpened2 :
      RunMotorOpening();
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        MotorStop();
        temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        state_ouverture_auto = autoOpen_wait_someTime3;
      }
      break;

    case autoOpen_wait_someTime3 :
      if ( (temps_actuel - temps_ouverture_auto) >= 3000ul )
      { //laisse la porte ouverte et remet la variable à l'état initial.
        state_ouverture_auto = autoOpen_idle0; //la variable repasse à 0
      }
      break;

    case autoOpen_idle0 :
      // just do nothing
      break;
  } //switch

} //task_ouverture_auto



void loop() {
  task_mesure_tensions();
  printToLCD();

  lcd_key = read_LCD_buttons();  // Lecture des touches
  // Sous traite les diff√©rentes t√Ęches
  switch (lcd_key)               // Action en cas de touche pressée
  {
    case btnRIGHT: //en appuyant sur le bouton RIGHT
      {
        if (!manualTestStarted) { // if this is a stateCHANGE
          manualTestStarted = true;
          state_relais_manuel = manuel_startClosingDoor1;
        }
        break;
      }
  }

  if (manualTestStarted) {
    task_relais_manuel();
  }


  // if lightsensor detects sunrise and doorsensor does not yet report door opened
  if (itIsDay && !digitalRead(CapteurHAUT) ) {
    task_ouverture_auto(); // open door
  }

  // if lightsensor detects night and doorsensor does not yet report door closed
  if (!itIsDay && !digitalRead(CapteurBAS) ) {
    task_fermeture_auto(); // close door
  }
} // end of function loop

best regards Stefan

Thanks for the program.

I think you're right, and I need to use some new variables, like whether it's day or night, or when the door is properly closed or open.

I allowed myself to modify the program a little:

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield

#include <LiquidCrystal.h>

// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
#define CapteurBAS 11 //le port numérique D11 est connecté au capteur BAS
#define CapteurHAUT 12 //le port numérique D12 est connecté au capteur HAUT

int state_relais_manuel = 0;
int state_fermeture_auto = 0;
int state_ouverture_auto = 0;
int state_seuil_ensoleillement;

unsigned long temps_mesures = 0;
unsigned long temps_relais_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;

boolean itIsDay;   // c_est_le_jour;
boolean manualTestStarted = false;

const byte manuel_stateMachineIdle0 = 0;
const byte manuel_startClosingDoor1 = 1;
const byte manuel_waitForSensorDownClosed2 = 2;
const byte manuel_openDoorAfterWaiting3 = 3;
const byte manuel_waitForSensorDoorUp4 = 4;
const byte manuel_waitAndStopStateMachine5 = 5;

const byte autoclose_waitSomeTime1 = 1;
const byte autoclose_wait_SensorDownclosed2 = 2;
const byte autoclose_wait_someTime3 = 3;
const byte autoclose_idle0 = 0;

const byte autoOpen_waitSomeTime1 = 1;
const byte autoOpen_wait_SensorOpened2 = 2;
const byte autoOpen_wait_someTime3 = 3;
const byte autoOpen_idle0 = 0;


// Fonction de lecture des touches
int read_LCD_buttons() { //permet de contr√īler les boutons de l'afficheur LCD

  adc_key_in = analogRead(0);   // Lecture du port analogique

  // Les valeurs qui suivent doivent être adaptées au shield
  if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
  if (adc_key_in < 50)   return btnRIGHT;     // 0
  if (adc_key_in < 195)  return btnUP;        // 99
  if (adc_key_in < 380)  return btnDOWN;      // 255
  if (adc_key_in < 555)  return btnLEFT;      // 409
  if (adc_key_in < 790)  return btnSELECT;    // 640

  return btnNONE;
}

void setup() {
  // On met les pin de chaque relais en sortie
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);

  pinMode(CapteurBAS, INPUT);
  pinMode(CapteurHAUT, INPUT);

  lcd.begin(16, 2);            // Démarrage de l'écran
  lcd.setCursor(0, 0);         // Positionnement du curseur au début
  lcd.print("Mesure tension"); // Message
}

void printToLCD() {

 // lcd.print("L");

  if (itIsDay) 
  {
    lcd.print("jour"); //affiche la valeur de l'état de la cellule solaire
  }
  else if (!itIsDay) 
  {
    lcd.print("nuit"); //affiche la valeur de l'état de la cellule solaire
  }

  lcd.print(" F");
  lcd.print(state_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique

  lcd.print(" O");
  lcd.print(state_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique

  lcd.print(" M");
  lcd.print(state_relais_manuel); //affiche la valeur de l'état du mode manuel de la porte

} // printToLCD

void task_mesure_tensions() { //permet de prendre des mesures de tensions et d'afficher des données sur l'écran LCD
  // Transforme la mesure (nombre entier) en tension via un produit en croix
  int solarCellADC = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
  int motorADC     = analogRead(A2); // Mesure la tension consommée par le moteur

  float solarCellVoltage = (float)solarCellADC * (5.0 / 1023.0);
  float motorVoltage     = (float)motorADC     * (5.0 / 1023.0);

  // Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
  lcd.setCursor(0, 1);           // Positionnement du curseur début de ligne

  if (solarCellVoltage < 1.0) 
  { // une tension basse signifie qu'il commence à faire sombre
    if (itIsDay) { // s'il s'asit d'un changement d'état jour-nuit
      itIsDay = false; //la variable passe à false lorsqu'il fait nuit
      // démarrer la machine à état pour fermer automatiquement la porte
      state_fermeture_auto = autoclose_waitSomeTime1;
    }
  }
  
  else if (solarCellVoltage >= 1.0)
  { // une tension haute signifie que le soleil se lève
      if (!itIsDay) { // s'il s'asit d'un changement d'état nuit-jour
        itIsDay = true;  //la variable passe à true lorsqu'il fait jour
        // démarrer la machine à état pour ouvrir automatiquement la porte
        state_ouverture_auto = autoOpen_waitSomeTime1;
      }
  }  
}

void RunMotorClosing() {
  digitalWrite(RelayPin1, LOW); //le relais 1 est actif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void MotorStop() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void RunMotorOpening() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, LOW); //le relais 2 est actif
}


void task_relais_manuel() { //permet d'activer le test de fonctionnement manuel de la porte
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( state_relais_manuel )
  {
    case manuel_startClosingDoor1 :
      // Après l'appui du bouton, le moteur tourne dans un sens et la porte commence à se fermer...
      RunMotorClosing();
      temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
      state_relais_manuel = manuel_waitForSensorDownClosed2; // the names already explain what happends
      break;

    case manuel_waitForSensorDownClosed2 :
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { //...le moteur se met en pause et la porte s'arrête pendant 3 secondes...
        MotorStop();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_openDoorAfterWaiting3; // the names already explain what happends
      }
      break;

    case manuel_openDoorAfterWaiting3 :
      if ( (temps_actuel - temps_relais_manuel) >= 3000ul )
      { //une fois la pause finie, le moteur tourne dans l'autre sens et la porte commence à s'ouvrir...
        RunMotorOpening();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_waitForSensorDoorUp4; // the names already explain what happends
      }
      break;

    case manuel_waitForSensorDoorUp4 :
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // ...le moteur se met en pause et la porte s'arrête pendant 3 secondes
        MotorStop();
        temps_relais_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        state_relais_manuel = manuel_waitAndStopStateMachine5; // the names already explain what happends
      }
      break;

    case manuel_waitAndStopStateMachine5 :
      if ( (temps_actuel - temps_relais_manuel) >= 3000ul )
      { //reviens à l'état initial après 3 secondes de pause
        state_relais_manuel = manuel_stateMachineIdle0; // the names already explain what happends
      }
      break;

    case manuel_stateMachineIdle0 :
      manualTestStarted = false; // manual cycle finished reset variable to false
      break;
  }//switch

}//task_relais_manuel



void task_fermeture_auto () { //permet d'activer la fermeture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( state_fermeture_auto )
  {
    case autoclose_waitSomeTime1 :
      if ( (temps_actuel - temps_fermeture_auto) < 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        state_fermeture_auto = autoclose_wait_SensorDownclosed2;
      }
      break;

    case autoclose_wait_SensorDownclosed2 :
      RunMotorClosing();
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        MotorStop();
        temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        state_fermeture_auto = autoclose_wait_someTime3; 
      }
      break;

    case autoclose_wait_someTime3 :
      if ( (temps_actuel - temps_fermeture_auto) >= 3000ul )
      { //laisse la porte fermée et remet la variable à l'état initial.
        state_fermeture_auto = autoclose_idle0;
      }
      break;

    case autoclose_idle0:
      // just do nothing
      break;
  } //switch

} //task_fermeture_auto



void task_ouverture_auto () { //permet d'activer l'ouverture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( state_ouverture_auto )
  {
    case autoOpen_waitSomeTime1 :
      if ( (temps_actuel - temps_fermeture_auto) < 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        state_ouverture_auto = autoOpen_wait_SensorOpened2;
      }
      break;

    case autoOpen_wait_SensorOpened2 :
      RunMotorOpening();
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        MotorStop();
        temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        state_ouverture_auto = autoOpen_wait_someTime3;
      }
      break;

    case autoOpen_wait_someTime3 :
      if ( (temps_actuel - temps_ouverture_auto) >= 3000ul )
      { //laisse la porte ouverte et remet la variable à l'état initial.
        state_ouverture_auto = autoOpen_idle0; //la variable repasse à 0
      }
      break;

    case autoOpen_idle0 :
      // just do nothing
      break;
  } //switch

} //task_ouverture_auto



void loop() {
  task_mesure_tensions();
  printToLCD();

  lcd_key = read_LCD_buttons();  // Lecture des touches
  // Sous traite les diff√©rentes t√Ęches
  switch (lcd_key)               // Action en cas de touche pressée
  {
    case btnRIGHT: //en appuyant sur le bouton RIGHT
      {
        if (!manualTestStarted) { // if this is a stateCHANGE
          manualTestStarted = true;
          state_relais_manuel = manuel_startClosingDoor1;
        }
        break;
      }
  }

  if (manualTestStarted) {
    task_relais_manuel();
  }


  // if lightsensor detects sunrise and doorsensor does not yet report door opened
  if (itIsDay && !digitalRead(CapteurHAUT) ) {
    task_ouverture_auto(); // open door
  }

  // if lightsensor detects night and doorsensor does not yet report door closed
  if (!itIsDay && !digitalRead(CapteurBAS) ) {
    task_fermeture_auto(); // close door
  }
} // end of function loop

I am testing the program but, strangely, it is now "jour" which only shows up on the LCD screen regardless of the brightness (even below 1 V).

It also displays ‚ÄúF0 O1 M0‚ÄĚ, but nothing happens 10 seconds later, ie no automatic closing.

Also, when I test manual operation by pushing the button, the door just closes to the DOWN sensor, and nothing more, it gets stuck on M3 without opening.

What would you advise me to do?

I propose to add new while conditions for the automatic closing and opening functions, like my personal program.

For example, for task_fermeture_auto (), it would be necessary that for at least 10 seconds, the variables manuel_startClosingDoor1 || autoOpen_waitSomeTime1 are not enabled to close the door. Otherwise, temps_fermeture_auto = temps_actuel and autoclose_idle0 is enabled.

I would like to know your opinion please

before anything else I want to know
Have you ever used
Serial.print()

to analyse what is going on in your code?

serial output can show much more information than your display.
You would have to modify your code again and again to show all kinds of informations on the LC-Display.
With serial-output you just add another line and you can see more.

what I recommend is adding serial-output.
Seeing what your code really does will guide you to that line of code that
is interesting. And then you start analysing why does it behave that way?

After stepping back and looking new at the loop-function.
The version I have posted does execute

task_relais_manuel();
and
task_ouverture_auto(); / task_fermeture_auto();

after each other.

executing the manual-statemachine / the auto-state-machine should be mutually exclusive.

I think this is a first step that should be corrected.
Running both state-machines in concurrence will have side-effects that will go immidiately away if this bug is corrected.

You should think about how switching between manual-mode and automatik-mode shall be done.

best regards Stefan

I don't understand what you mean by that.
I highly recommend that you describe the functionality by just using normal words and cosnequently avoiding programming terms.

The reason is: You still have some MISconceptions about programming!

You wrote

manuel_startClosingDoor1 and autoOpen_waitSomeTime1 are NO variables
they are CONSTANTS These constants are NOT "enabled"

Using a while-loop destroys the functionality of the state-machine.

And that's why I insist on that you describe the functionality that you want to have in NORMAL WORDS and AVOID any programming-terms.

There wil be time enough to use programming-terms.
At the moment using programming-terms leads to new misunderstandings and UNclearness and this is just waisting time.

We could have been five steps forward if you would accept my recommendations.

here is a code-snippet that I used for analysing why your code was stuck in state

    case autoclose_waitSomeTime1 :
      // standard use of non-blocking timing with millis is:
      // calculate difference between actual time and a snapshot of time
      // that marks the begin of a waiting-time
      // if difference becomes                 BIGGER than the waiting-time the if-condition becomes true
      unsigned long difference = temps_actuel - temps_fermeture_start;
      debugTxtVar("temps_actuel - temps_fermeture_start " ,difference);
      debugTxtVar("temps_actuel " ,temps_actuel);
      debugTxtVar("temps_fermeture_start " ,temps_fermeture_start);
      debugTxtVar("millis()" ,millis());

The debug-output CLEARLY showed what is really happening.
et voilà! bug found and corrected

After maybe one hour of testing with some more corrections the program is working now. As it is your task to develop the program I will only post this code-version if you have posted the functional description in normal words.

best regards Stefan

I am still working for my program.

You know, I put comment lines to explain what I'm doing, but I don't want to focus on changing the names of the variables. I have my own way of finding my way.

Another thing, I understood that to better regulate the flow of time in my program, you suggest that I create a new variable called "difference" where difference = temps_actuel - temps_fermeture_start.

But I don't understand this debugTxtVar function that you used ... What is it for?

I inserted this just for debugging purposes.

The name says what the purpose is: debugging.
it reduces typing five lines of code that do print to the serial interface to a single line.

You have your arduino connected to your computer with a USB-cable for uploading your program into the flash-memory of the arduino.

The exact same USB-cable can be used to send data from the Arduino to your Computer

Arduino-----USB-cable------------> Computer
And there is a super-easy way to display this data on your screen:

The serial monitor of the Arduino-IDE. It is the windows you can see in the picture on the right half of the screen.

If you press Ctrl-Shift-M or choose

Will open the window with the serial-monitor

Inside function setup you write

void setup() {
  Serial.begin(115200);

to start the serial-interface.
Almost the same as starting the LCD
This serial interface works completely independent and in parallel to your LCD

after the serial.begin at any place in your code you can add
lines like

  Serial.println("This is my debug-output");

very similar to printing to your LCD only you can print 2000 characters in one line if you want to
and you can print as many lines as you like to the serial monitor. Even thousands of lines even at high speed.

Using the serial monitor makes debugging much much easier.

best regards Stefan

heya, I made a few more modifications:

//moteur + relais + LCD + cellule + capteurs

// LCD Keypad Shield

#include <LiquidCrystal.h>

// Création de l'objet lcd (avec les différents ports numériques qu'il utilise)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//variables
int lcd_key     = 0;
int adc_key_in  = 0;
int TensionBAS  = 0;
int TensionHAUT = 0;

//constantes
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

#define RelayPin1 2 //le port numérique D2 est connecté au relais 1
#define RelayPin2 3 //le port numérique D3 est connecté au relais 2
#define CapteurBAS 11 //le port numérique D11 est connecté au capteur BAS
#define CapteurHAUT 12 //le port numérique D12 est connecté au capteur HAUT

#define debugTxtVar(myParameterText, variableName) \
        Serial.print(#myParameterText " " #variableName"="); \
        Serial.println(variableName); 

int Etat_fonctionnement_manuel = 0;
int Etat_fermeture_auto = 0;
int Etat_ouverture_auto = 0;
//int Etat_seuil_ensoleillement;

unsigned long temps_mesures = 0;
unsigned long temps_fonctionnement_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;

boolean JourVrai;   // c_est_le_jour;
boolean Test_manuel_demarrage = false;

const byte manuel_Machine_inactive0 = 0;
const byte manuel_debut_fermeture_porte1 = 1;
const byte manuel_Attendre_CapteurBAS_ferme2 = 2;
const byte manuel_Ouvrir_porte_apresTempo3 = 3;
const byte manuel_Attendre_CapteurHAUT_ferme4 = 4;
const byte manuel_arret_machine_apresTempo5 = 5;

const byte autoFermeture_attendre_tempoSoir1 = 1;
const byte autoFermeture_debut_fermeture2 = 2;
const byte autoFermeture_CapteurBAS_ferme3 = 3;
const byte autoFermeture_arret_machine4 = 4;
const byte autoFermeture_machine_inactive0 = 0;

const byte autoOuverture_attendre_tempoMatin1 = 1;
const byte autoOuverture_debut_ouverture2 = 2;
const byte autoOuverture_CapteurHAUT_ferme3 = 3;
const byte autoOuverture_arret_machine4 = 4;
const byte autoOuverture_machine_inactive0 = 0;


void setup() {
  // On met les pin de chaque relais en sortie
  pinMode(RelayPin1, OUTPUT);
  pinMode(RelayPin2, OUTPUT);

  pinMode(CapteurBAS, INPUT);
  pinMode(CapteurHAUT, INPUT);

  Serial.begin(9600);

  lcd.begin(16, 2);            // Démarrage de l'écran
  lcd.setCursor(0, 0);         // Positionnement du curseur au début
  lcd.print("Mesure tension"); // Message
}


void loop() {
  task_mesure_tensions();
  AffichageLCD();

  lcd_key = read_LCD_buttons();  // Lecture des touches
  // Sous traite les diff√©rentes t√Ęches
  switch (lcd_key)               // Action en cas de touche pressée
  {
    case btnRIGHT: //en appuyant sur le bouton RIGHT
      {
        if (!Test_manuel_demarrage) { // si le test manuel n'a pas déjà démarré
          Test_manuel_demarrage = true;
          Etat_fonctionnement_manuel = manuel_debut_fermeture_porte1;
        }
        break;
      }
  }

  if (Test_manuel_demarrage) {
    task_fonctionnement_manuel();
  }

  // si la cellule solaire détecte le jour et que le capteur ne détecte pas la porte ouverte
  if (JourVrai && digitalRead(CapteurHAUT) == HIGH ) {
    task_ouverture_auto(); // open door
  }

  // si la cellule solaire détecte la nuit et que le capteur ne détecte pas la porte fermée
  if (!JourVrai && digitalRead(CapteurBAS) == HIGH ) {
    task_fermeture_auto(); // close door
  }
} // fin de la boucle

void AffichageLCD() {

    unsigned long temps_actuel = millis();
 
    // Affiche la mesure de la tension sur l'écran LCD et attends 250 ms
    lcd.setCursor(0, 1);           // Positionnement du curseur début de ligne

    if( (temps_actuel - temps_mesures) >= 1000ul )
    {
        temps_mesures = temps_actuel;

        // lcd.print("L");

        if (JourVrai) 
        {
          lcd.print("jour"); //affiche la valeur de l'état de la cellule solaire
        }
        else if (!JourVrai) 
        {
          lcd.print("nuit"); //affiche la valeur de l'état de la cellule solaire
        }
      
        lcd.print(" F");
        lcd.print(Etat_fermeture_auto); //affiche la valeur de l'état de la fermeture automatique
      
        lcd.print(" O");
        lcd.print(Etat_ouverture_auto); //affiche la valeur de l'état de l'ouverture automatique
      
        lcd.print(" M");
        lcd.print(Etat_fonctionnement_manuel); //affiche la valeur de l'état du mode manuel de la porte

         debugTxtVar("F=  ", Etat_fermeture_auto);
         //Serial.println(Etat_fermeture_auto);
      
         debugTxtVar("O= ", Etat_ouverture_auto);
         //Serial.println(Etat_ouverture_auto);
      
         debugTxtVar("M= ", Etat_fonctionnement_manuel);
         //Serial.println(Etat_fonctionnement_manuel);
    }
} // AffichageLCD

void task_mesure_tensions() { //permet de prendre des mesures de tensions et d'afficher des données sur l'écran LCD
  // Transforme la mesure (nombre entier) en tension via un produit en croix
  int CelluleSolaireCAN = analogRead(A1); // Mesure la tension aux bornes de la cellule solaire
  int MoteurCAN     = analogRead(A2); // Mesure la tension consommée par le moteur

  float TensionCelluleSolaire = (float)CelluleSolaireCAN * (5.0 / 1023.0);
  float TensionMoteur    = (float)MoteurCAN     * (5.0 / 1023.0);


  if (TensionCelluleSolaire < 1.0) 
  { // une tension basse signifie qu'il commence à faire sombre
    if (JourVrai) { // s'il s'asit d'un changement d'état jour-nuit
      JourVrai = false; //la variable passe à false lorsqu'il fait nuit
      // démarrer la machine à état pour fermer automatiquement la porte
      Etat_fermeture_auto = autoFermeture_attendre_tempoSoir1;
      Etat_ouverture_auto = autoOuverture_machine_inactive0;
    }
  }
  
  else if (TensionCelluleSolaire >= 1.0)
  { // une tension haute signifie que le soleil se lève
      if (!JourVrai) { // s'il s'asit d'un changement d'état nuit-jour
        JourVrai = true;  //la variable passe à true lorsqu'il fait jour
        // démarrer la machine à état pour ouvrir automatiquement la porte
        Etat_ouverture_auto = autoOuverture_attendre_tempoMatin1;
        Etat_fermeture_auto = autoFermeture_machine_inactive0;
      }
  }  
}

void FermerMoteur() {
  digitalWrite(RelayPin1, LOW); //le relais 1 est actif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void ArretMoteur() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, HIGH); //le relais 2 est inactif
}

void OuvrirMoteur() {
  digitalWrite(RelayPin1, HIGH); //le relais 1 est inactif
  digitalWrite(RelayPin2, LOW); //le relais 2 est actif
}


void task_fonctionnement_manuel() { //permet d'activer le test de fonctionnement manuel de la porte
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( Etat_fonctionnement_manuel )
  {
    case manuel_debut_fermeture_porte1 :
      // Après l'appui du bouton, le moteur tourne dans un sens et la porte commence à se fermer...
      FermerMoteur();
      temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
      Etat_fonctionnement_manuel = manuel_Attendre_CapteurBAS_ferme2; // on incrémente la variable de 1
      break;

    case manuel_Attendre_CapteurBAS_ferme2 :
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { //...le moteur se met en pause et la porte s'arrête pendant 3 secondes...
        ArretMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel = manuel_Ouvrir_porte_apresTempo3; // on incrémente la variable de 1
      }
      break;

    case manuel_Ouvrir_porte_apresTempo3 :
      if ( (temps_actuel - temps_fonctionnement_manuel) >= 3000ul )
      { //une fois la pause finie, le moteur tourne dans l'autre sens et la porte commence à s'ouvrir...
        OuvrirMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel = manuel_Attendre_CapteurHAUT_ferme4; // on incrémente la variable de 1
      }
      break;

    case manuel_Attendre_CapteurHAUT_ferme4 :
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // ...le moteur se met en pause et la porte s'arrête pendant 3 secondes
        ArretMoteur();
        temps_fonctionnement_manuel = temps_actuel;//on réinitialise le temps passé à 0 ms
        Etat_fonctionnement_manuel = manuel_arret_machine_apresTempo5; // on incrémente la variable de 1
      }
      break;

    case manuel_arret_machine_apresTempo5 :
      if ( (temps_actuel - temps_fonctionnement_manuel) >= 3000ul )
      { //reviens à l'état initial après 3 secondes de pause
        Etat_fonctionnement_manuel = manuel_Machine_inactive0; // la variable repasse à 0
      }
      break;

    case manuel_Machine_inactive0 :
      Test_manuel_demarrage = false; // boucle manuelle finie
      break;
  }//switch

}//task_fonctionnement_manuel



void task_fermeture_auto () { //permet d'activer la fermeture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( Etat_fermeture_auto )
  {
    case autoFermeture_attendre_tempoSoir1 :
      if ( (temps_actuel - temps_fermeture_auto) >= 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        Etat_fermeture_auto = autoFermeture_debut_fermeture2; //on incrémente la variable de 1
      }
      break;

    case autoFermeture_debut_fermeture2 :
      FermerMoteur();
      // la porte se met à se fermer
      temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
      Etat_fermeture_auto = autoFermeture_CapteurBAS_ferme3; //on incrémente la variable de 1
      break;

     case autoFermeture_CapteurBAS_ferme3 :
      if ( digitalRead(CapteurBAS) == LOW  ) //lorsque le contact du capteur BAS est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        ArretMoteur();
        temps_fermeture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        Etat_fermeture_auto = autoFermeture_arret_machine4; //on incrémente la variable de 1
      }
      break;  

    case autoFermeture_arret_machine4 :
      if ( (temps_actuel - temps_fermeture_auto) >= 3000ul )
      { //laisse la porte fermée et remet la variable à l'état initial.
        Etat_fermeture_auto = autoFermeture_machine_inactive0; // la variable repasse à 0
      }
      break;

    case autoFermeture_machine_inactive0:
      // rien ne se passe
      break;
  } //switch

} //task_fermeture_auto



void task_ouverture_auto () { //permet d'activer l'ouverture automatique de la porte avec le seuil de luminosité
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

  switch ( Etat_ouverture_auto )
  {
    case autoOuverture_attendre_tempoMatin1 :
      if ( (temps_actuel - temps_fermeture_auto) >= 10000ul)
      { //tant que les 10 secondes ne se soient pas découlées...
        Etat_ouverture_auto = autoOuverture_debut_ouverture2; //on incrémente la variable de 1
      }
      break;

    case autoOuverture_debut_ouverture2 :
      OuvrirMoteur();
      // la porte se met à s'ouvrir
      temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
      Etat_ouverture_auto = autoOuverture_CapteurHAUT_ferme3; //on incrémente la variable de 1
      
      break;

    case autoOuverture_CapteurHAUT_ferme3 :
      if ( digitalRead(CapteurHAUT) == LOW  ) //lorsque le contact du capteur HAUT est fermé...
      { // le moteur se met en pause et la porte s'arrête.
        ArretMoteur();
        temps_ouverture_auto = temps_actuel; //on réinitialise le temps passé à 0 ms
        Etat_ouverture_auto = autoOuverture_arret_machine4; //on incrémente la variable de 1
      }
      break;  

    case autoOuverture_arret_machine4 :
      if ( (temps_actuel - temps_ouverture_auto) >= 3000ul )
      { //laisse la porte ouverte et remet la variable à l'état initial.
        Etat_ouverture_auto = autoOuverture_machine_inactive0; //la variable repasse à 0
      }
      break;

    case autoOuverture_machine_inactive0 :
      // rien ne se passe
      break;
  } //switch

} //task_ouverture_auto





// Fonction de lecture des touches
int read_LCD_buttons() { //permet de contr√īler les boutons de l'afficheur LCD

  adc_key_in = analogRead(0);   // Lecture du port analogique

  // Les valeurs qui suivent doivent être adaptées au shield
  if (adc_key_in > 1000) return btnNONE;   // En principe 1023 quand aucune touche n'est pressée
  if (adc_key_in < 50)   return btnRIGHT;     // 0
  if (adc_key_in < 195)  return btnUP;        // 99
  if (adc_key_in < 380)  return btnDOWN;      // 255
  if (adc_key_in < 555)  return btnLEFT;      // 409
  if (adc_key_in < 790)  return btnSELECT;    // 640

  return btnNONE;
}

As you know, there are 3 variables that allow you to control the manual and automatic modes of the door:

-Etat_fonctionnement_manuel
-Etat_fermeture_auto = 0;
-Etat_ouverture_auto = 0;

I know, it's in French.

Each of these are assigned by a value depending on which constant on the compare each.

For Etat_fonctionnement_manuel:
-manuel_Machine_inactive0 = 0;
-manuel_debut_fermeture_porte1 = 1;
-manuel_Attendre_CapteurBAS_ferme2 = 2;
-manuel_Ouvrir_porte_apresTempo3 = 3;
-manuel_Attendre_CapteurHAUT_ferme4 = 4;
-manuel_arret_machine_apresTempo5 = 5;

For Etat_fermeture_auto:
-autoFermeture_attendre_tempoSoir1 = 1;
-autoFermeture_debut_fermeture2 = 2;
-autoFermeture_CapteurBAS_ferme3 = 3;
-autoFermeture_arret_machine4 = 4;
-autoFermeture_machine_inactive0 = 0;

For Etat_ouverture_auto:
-autoOuverture_attendre_tempoMatin1 = 1;
-autoOuverture_debut_ouverture2 = 2;
-autoOuverture_CapteurHAUT_ferme3 = 3;
-autoOuverture_arret_machine4 = 4;
-autoOuverture_machine_inactive0 = 0;

I allowed myself to create new constants in order to separate the tasks to close or open the door automatically AND wait for the door to reach the respective sensor.

To go faster, with my serial print and my LCD screen, I display M for Etat_fonctonnement_manuel, F for Etat_fermeture_auto, and O for Etat_ouverture_auto.

To test my program with the voltage threshold of the solar cell, I use a light for the day and turn it off to simulate at night.

I then do tests where I feed my assembly with the USB port by choosing a different starting "time of day".

For example, when I power the assembly up at night, then turn the lamp back on before turning it off again, I'll observe the values of F and O.

And conversely, when I feed the assembly first during the day, I then turn off the lamp, then I turn it on again while taking the values F and O.

Normally, I added if conditions to prevent F and O from having the same value. So if one is 0, the other is 1.

However, here is the test I performed:

Test Nuit-jour-nuit Test Jour-nuit-jour
F O F O
Nuit1 0 0 Jour1 0 1
Jour 0 1 Nuit 1 0
Nuit2 1 0 Jour2 0 1

When starting the program at night, F and O are both equal to O. But changing the period, if one is 0, the other is 1.
However, starting at night, there is not the same problem. Get it ?

I believe there is a problem with the constant autoFermeture_attendre_tempoSoir1

Another problem, normally I add a 10 second tempo to open or close the door if it is day or night.

However, by waiting for at least 10 seconds, nothing happens. But if I change the time period, the door opens or closes at that time depending on the period that we have switched.

Could you help me please?

Thank you in advance.

make all variables that deal somehow with millis() global.

This means the variable temps_actuel is defined inside the function task_fonctionnement_manuel

put the definition outside the function

void task_fonctionnement_manuel() { //permet d'activer le test de fonctionnement manuel de la porte
  // if values of a variable shall be re-used the variable must be assigned
  // global or with attribute static to keep the value even after leaving the function
  static unsigned long temps_actuel = millis();

the definition is unsigned long temps_actuel

the assigning a value is temps_actuel = millis();

So the definition should be here
unsigned long temps_mesures = 0;
unsigned long temps_fonctionnement_manuel = 0;
unsigned long temps_fermeture_auto = 0;
unsigned long temps_ouverture_auto = 0;

unsigned long temps_actuel;

add debugoutput at th top of each state-machine
example

void task_fonctionnement_manuel() { //permet d'activer le test de fonctionnement manuel de la porte
  // if values of a variable shall be re-used the variable must be defined GLOBAL
  temps_actuel = millis();
  debugTxtVar("task_fonctionnement_manuel ", Etat_fonctionnement_manuel);
delay(1000); // slow down serial output

If I should do a deeper analysis of your code add english names as comments
for each variable and each function-name

You want it to code your way. ANd you want help he "price" for my help is english comments.

best regards Stefan