Perte de connection WEmos D1 => reconnection wifi automatique

Bonjours à tous, avant de vous expliquer la problématique, je vous explique mo nsystème. J’ai une carte Wemos D1 qui pilote des relais pour de la domotique. Ma carte Wemos se connecte en wifi à ma box pour que à distance (via une appli sur téléphone), je puisse lui envoyer des requête.

Depuis quelques jours, je suis confronté à une problématique aléatoire sur mon système. En effet, j’ai de temps en temps des pertes de connection qui font que je ne peux plus envoyer de requête à ma carte. Je pense à une perte de la connection wifi.

Je vous joint le programme complet. Auriez-vous une idée pour régler le problème ? est ce qu’il faut que je rajoute une reconnexion automatique au wifi si je pers cette connexion ?

Merci par avance.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <OneWire.h>
#include <DallasTemperature.h>
/************** informations sur le programme *******/

//*********** initialisation des variables liées au relais **************//

const int OneWireBus = 14;                    //Bus One Wire permettant la mesure de la temp
const int pinRelais1CoupureRegulateur = 4;    // relais 1 permettant la coupure de la commande du régulateur DeltaDore (D4 => GPIO4)
const int pinRelais2CoupureRegulateur = 5;    // relais 2 permettant la coupure de la commande du régulateur DeltaDore (D3 => GPIO5)
const int pinRelais1Commande = 12;            // relais 1 permettant le pilotage du chauffage (D6 => GPIO12)
const int pinRelais2Commande = 15;            // relais 2 permettant le pilotage du chauffage (D10 => GPIO15)
const int pinRelais3Portail = 13;            // relais 3 permettant le pilotage du portail (D7 => GPIO13)
const int ledCommande = 2;                   // led permettant la visualisation du relais de commande (D9 => GPIO2)
const int statut_portail = 16 ;             // input permettant de connaitre le statut du portail (ouvert ou fermé) (D2 => GPIO16)
char* mode_pilotage = "";                     //Défini le type de pilotage : mode Eco ou confort
char* pilotage = "";                          //Défini le pilotage : Arduino ou régulateur DeltaDore
char* pilotage_portail = "";                          //Défini le pilotage : Arduino ou régulateur DeltaDore
int moyenne_value=0;
int value=0;
time_t  bootTime;
char timeBuffer[80];

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(OneWireBus);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature DS18B20(&oneWire);
char temperatureCString[6];
String TempString;
String Text;

//initialisation des variables liées au wifi
const char* ssid = "XXXXXXXXXX";
const char* password = "XXXXXXXXX";
// the IP address for the shield:
IPAddress ip(XXX, XXX, X, XXX); // where xx is the desired IP Address
IPAddress gateway(XXX, XXX, X, XXX); // set gateway to match your network
IPAddress subnet(XXX, XXX, XXX, X); // set subnet mask to match your network
ESP8266WebServer server(80); // on instancie un serveur ecoutant sur le port 80



//********************** programme principal ***********************//
void setup(void)
{
  //Configuration des pins de la carte
  pinMode(pinRelais1CoupureRegulateur, OUTPUT);   // "pinRelais1CoupureRegulateur" configurée en sortie
  pinMode(pinRelais2CoupureRegulateur, OUTPUT);   // "pinRelais2CoupureRegulateur" configurée en sortie
  pinMode(pinRelais1Commande, OUTPUT);            // "pinRelais1Commande" configurée en sortie
  pinMode(pinRelais2Commande, OUTPUT);            // "pinRelais2Commande" configurée en sortie
  pinMode(pinRelais3Portail, OUTPUT);            // "pinRelais3Portail" configurée en sortie
  pinMode(ledCommande, OUTPUT);                   // "ledCommande" configurée en sortie
  pinMode(statut_portail, INPUT);               //"statut_portail" configuré en entrée
  analogRead(statut_portail);

  //Initialisation des relais au démarrage
  digitalWrite(pinRelais1CoupureRegulateur, LOW); // coupure du relais "pinRelais1CoupureRegulateur"
  digitalWrite(pinRelais2CoupureRegulateur, LOW); // coupure du relais "pinRelais2CoupureRegulateur"
  digitalWrite(pinRelais1Commande, LOW);          // coupure du relais "pinRelais1Commande"
  digitalWrite(pinRelais2Commande, LOW);          // coupure du relais "pinRelais2Commande"
  digitalWrite(pinRelais3Portail, LOW); // coupure du relais "pinRelais3Portail"
  digitalWrite(ledCommande, LOW);                 //éteindre "ledCommande"


  //Configuration du wifi
  Serial.begin(115200);

  DS18B20.begin(); // IC Default 9 bit.

  // on demande la connexion au WiFi
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(ssid, password);
  Serial.println("");
  // on attend d'etre connecte au WiFi avant de continuer
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  // on affiche l'adresse IP qui nous a ete attribuee
  Serial.println("");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());



  //***************************************** Coupure fil pilote, activation Arduino ****************************************//
  server.on("/ON", []()
  {
    if (pilotage != "arduino")
    {
      Text = "Coupure régulateur DeltaDore, activation Arduino \r\n";
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);

      digitalWrite(pinRelais1CoupureRegulateur, HIGH); // allumage du relais "pinRelais1CoupureRegulateur"
      digitalWrite(pinRelais2CoupureRegulateur, HIGH); // allumage du relais "pinRelais2CoupureRegulateur"
      digitalWrite(pinRelais1Commande, LOW);          // coupure du relais 1 "pinRelais1Commande"
      digitalWrite(pinRelais2Commande, LOW);          // coupure du relais 2 "pinRelais2Commande"
      digitalWrite(ledCommande, LOW);                 //eteindre "ledCommande" (actif à l'état haut)
      pilotage = "arduino";
      mode_pilotage = "eco";
    }
    else
    {
      Text = "Commande déjà activée \r\n";
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);
    }
  });

  //******************* Coupure Arduino, activation fil pilote ***************//
  server.on("/OFF", []()
  {
    if (pilotage != "regulateur")
    {
      Text = "Coupure Arduino, activation régulateur DeltaDore \r\n";
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);

      digitalWrite(pinRelais1CoupureRegulateur, LOW); // coupure du relais "pinRelais1CoupureRegulateur"
      digitalWrite(pinRelais2CoupureRegulateur, LOW); // coupure du relais "pinRelais2CoupureRegulateur"
      digitalWrite(pinRelais1Commande, LOW);          // coupure du relais 1 "pinRelais1Commande"
      digitalWrite(pinRelais2Commande, LOW);          // coupure du relais 2 "pinRelais2Commande"
      digitalWrite(ledCommande, LOW);                 //eteindre "ledCommande" (actif à l'état haut)
      pilotage = "regulateur";
      mode_pilotage = "eco";
    }
    else
    {
      Text = "Commande déjà activée \r\n";
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);
    }
  });

  //*********************** Mode confort ********************//
  server.on("/CONF", []()
  {
    if (pilotage == "arduino" && mode_pilotage != "conf")
    {
      Text = String("Pilotage Arduino => mode confort \r\n");
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);

      digitalWrite(pinRelais1Commande, HIGH);           // allumage du relais 1 "pinRelais1Commande"
      digitalWrite(pinRelais2Commande, HIGH);           // allumage du relais 2 "pinRelais2Commande"
      digitalWrite(ledCommande, HIGH);                  //allumer "ledCommande" (actif à l'état haut)
      mode_pilotage = "conf";
    }
    else
    {
      Text = "Commande non autorisée : vérifier que la commande ne soit pas déjà activée ou que le pilotage soit bien en mode 'arduino' \r\n";
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);
    }
  });

  //*************************** Mode eco ***********************//
  server.on("/ECO", []()
  {
    if (pilotage == "arduino" && mode_pilotage != "eco")
    {
      Text = String("Pilotage Arduino => mode eco \r\n");
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);

      digitalWrite(pinRelais1Commande, LOW);          // coupure du relais 1 "pinRelais1Commande"
      digitalWrite(pinRelais2Commande, LOW);           // coupure du relais 2 "pinRelais2Commande"
      digitalWrite(ledCommande, LOW);                  //eteindre "ledCommande" (actif à l'état haut)
      mode_pilotage = "eco";
    }
    else
    {
      Text = "Commande non autorisée : vérifier que la commande ne soit pas déjà activée ou que le pilotage soit bien en mode 'arduino' \r\n";
      getTemperature();
      Text = Text + TempString;
      server.send(200, "text/plain", Text);
    }
  });

  //****************************** Statut du chauffage *********************//
  server.on("/STATUT", []()
  {
    if (pilotage == "regulateur")
    {
      Text = String("Pilotage régulateur\r\nMesure de la température : ");
    }
    else if (pilotage == "arduino")
    {
      if (mode_pilotage == "eco")
      {
        Text = String("Pilotage Arduino => mode eco\r\nMesure de la température : ");
      }
      else if (mode_pilotage == "conf")
      {
        Text = String("Pilotage Arduino => mode confort\r\nMesure de la température : ");
      }
      else
      {
        Text = String("Pilotage arduino\r\nMesure de la température : ");
      }
    }
    else
    {
      Text = String("Statut inconnu\r\nMesure de la température : ");
    }
    getTemperature();
    Text = Text + TempString;
    server.send(200, "text/plain", Text);
  });
  //******************** Pilotage portail ***********************//
  server.on("/PORTAIL", []()
  {
    Text = "Pilotage portail \r\n";
    
    server.send(200, "text/plain", Text);

    digitalWrite(pinRelais3Portail, HIGH); // allumage du relais "pinRelais3Portail"
    delay(500);
    digitalWrite(pinRelais3Portail, LOW); // coupure du relais "pinRelais3Portail"
  });

//*************************************************** Statut du portail **************************************************//
  server.on("/STATUT_PORTAIL", []()
  {
      for(int i=0;i<20;i++)
        {
          value=analogRead(statut_portail);
          /*if (digitalRead(statut_portail) == 1)
          {
            commute++;   
          }
          else
          {
            commute--;
          }*/
          moyenne_value = value + moyenne_value;
          delay(100);
        }

      moyenne_value=moyenne_value/20;  
      Serial.println(moyenne_value);
      if(moyenne_value >500)
      {
        Text = "Portail ouvert \r\n";
      }
      else if(moyenne_value == 0)
      {
        Text = "Portail fermé \r\n";
      }  
      else
      {
        Text = "Portail en mouvement \r\n";
      }
      
      moyenne_value = 0;
      server.send(200, "text/plain", Text);
  });
  // on commence a ecouter les requetes venant de l'extèrieur
  server.begin();
}

void getTemperature()
{
  float tempC;
  DS18B20.requestTemperatures();
  tempC = DS18B20.getTempCByIndex(0);
  tempC = tempC - 3.44;
  dtostrf(tempC, 2, 2, temperatureCString);
  delay(100);
  if (String(temperatureCString) == "-127.00" || String(temperatureCString) == "85.00")
  {
    TempString = "Attention => Erreur de lecture du capteur de température ";
  }
  else
  {
    //TempString = String(temperatureCString) + char(176) + "C";
    TempString = String(temperatureCString) + "°C";
  }
}

//*********************** boucle principale *******************//
void loop(void)
{
  // A chaque iteration, on appelle handleClient pour que les requetes soient traitees
  server.handleClient();
}

Vous pouvez toujours essayer de mettre une reconnection

void loop()
{
  if(WiFi.status() != WL_CONNECTED)
  {
    WiFi.disconnect();
    WiFi.begin(ssid, password);
  }

  server.handleClient();
}

Votre handler status est long avec 20 delay de 100ms - ça peut créer des soucis si vous ne revenez pas rapidement à la loop pour donner la main à la stack qui gère le wifi en arrière plan pour vous. Éventuellement mettez des delay plus courts et appeler yield() entre temps

Bonjour @J-M-L,
Par curiosité et surtout parce que j'ai du mal à comprendre le peu de doc que je trouve à ce sujet, à quoi sert la fonction yield exactement ?

Bonne fin de journée,
Pandaroux007

EDIT : je lis sur téléphone donc tout ce qui suit ne sont que de pures spéculations de néophyte. Première question, une partie des variables suivent le camelCase et une autre le snake_case, c'est très mineur mais pourquoi ne pas utiliser une seule convention ?

Deuxièmement, à quoi sert le analogRead ici ? (Si c'est dans le but d'activer la résistance de tirage interne qui est, je crois, présente sur le D1 mini, vous pouvez utiliser INPUT_PULLUP)

Ici j'ai lu en diagonale mais vous utilisez des valeurs en dur dans le code, peut-être qu'un enum serait plus lisible comme dans le cas d'une machine à état (+ éventuellement switch/case) ?


Effectivement comme l'a souligné @J-M-L, il y a pas mal de delay (donc du code bloquant), pas idéal dans le cas d'un serveur web - même si ce n'est probablement pas la cause des déconnexions, il faudrait voir à changer la logique ici et là (utiliser millis notamment mais peut-être être aussi déplacer certaines choses en utilisant des variables "drapeaux" pour ensuite traiter les changements dans la loop ?)

Sur AVR, la fonction yield() n’a pas d’effet fonctionnel et le compilateur peut optimiser l’appel en le supprimant (voyez cela comme une fonction qui ne fait rien).

Sur des architectures comme l’ESP8266 , où il existe une couche système avec ordonnanceur coopératif, yield() sert à volontairement rendre la main au système. Cela permet notamment à l’OS de traiter des tâches internes comme le maintien de la pile Wi-Fi ou la gestion d’autres elements systèmes avant de reprendre l’exécution du programme utilisateur.

En l’absence d’OS préemptif, cette fonction introduit donc un point explicite où le code accepte de céder temporairement l’exécution au runtime système - ça évite par exemple de déclencher le watchdog quand on attend trop longtemps un événement particulier par exemple.

Bonjour à tous,

merci pour vos propositions. J'ai modifié mon code dans ce sens. J'ai relancé l'appli et je vous tiens au courant si plus de "timeout"