MQTT avec delay dans boucle FOR sur ESP8266

Bonjour,
Je suis débitant en arduino et je bloque sur le programme de mon robot de piscine sur ESP8266

Tout fonctionne bien tant que mon délais temps ne dépasse pas 8000.
La fonction " client.publish("ESP_Robot_Piscine/Avancement%", Avancement);" marche bien
Si je modifie les valeurs dans "temps=(random(3000,6000)); " en passant à temps=(random(30000,60000)); je n'ai pas de message sur mon serveur mqtt.

J'ai vu effectivement que delay peut etre bloquant et que l'on peut utiliser millis à la place mais la je ne trouve pas car en plus je suis dans une boucle for.
Merci par avance de votre aide
Stéphane

void loop() {
  client.loop();
  
  BP=digitalRead(BPMA);
  digitalWrite(LEDOFF, HIGH);
  digitalWrite(LEDON, LOW);
  
  if ((BP)==1) {
    Serial.println("**** DEMARRAGE DU CYCLE ****");
    client.publish("ESP_Robot_Piscine/Etat", "1"); 
    digitalWrite(LEDOFF, LOW);
    digitalWrite(LEDON, HIGH); 
    digitalWrite(Pompe, LOW); // Attention commande inversée Low à la place de High
    Serial.println("Pompe en marche");
    delay(6000);  
  
    for (int i = 1; i <= N; i++) {
               
      digitalWrite(MAV, LOW);  
      digitalWrite(MAR, HIGH);  
      Serial.println("Marche AVANT");
      temps=(random(3000,6000));  // A modifier en fonction taille piscine et si plus fond que paroies
      delay(temps);
         
        // Arret de la pompe 8s pour faire tourner le robot de 90°
        if (i==N/3) {
        digitalWrite(Pompe, HIGH); 
        Serial.println("PAUSE 1 POMPE POUR TOURNER");
        delay(8000);
        digitalWrite(Pompe, LOW);
        }
      
      // Arret de la pompe 8s pour faire tourner le robot de 90°
        if (i==N/2) {
        digitalWrite(Pompe, HIGH); 
        Serial.println("PAUSE 2 POMPE POUR TOURNER");
        delay(8000);
        digitalWrite(Pompe, LOW);
        }
        
      digitalWrite(MAV, HIGH); 
      digitalWrite(MAR, HIGH); 
      delay(500);
           
      digitalWrite(MAV, HIGH); 
      digitalWrite(MAR, LOW);  
      Serial.println("Marche ARRIERE");
      temps=(random(3000,6000));  // A modifier en fonction taille piscine et si plus fond que paroies
      Serial.print(temps/1000);
      Serial.println("sec");  
      delay(temps);      

  
      digitalWrite(MAV, HIGH);  
      digitalWrite(MAR, HIGH);  
      Serial.println("PAUSE"); 
      delay(500);       

      Serial.print("i= ");
      Serial.println(i);
      Serial.print("%= ");
      Serial.print(i*100/N);
      Serial.println("%"); 

      
     
      // Convert the value to a char array
      char Avancement[8];
      dtostrf(i*100/N, 1, 0, Avancement);
      client.publish("ESP_Robot_Piscine/Avancement%", Avancement);
        
    }
  
     Serial.println("**** FIN DU CYCLE ****");
     client.publish("ESP_Robot_Piscine/Etat", "0"); 
     client.publish("ESP_Robot_Piscine/Avancement%", "0");

   
   }
       
   digitalWrite(LEDOFF, HIGH);  
   digitalWrite(LEDON, LOW);    
   digitalWrite(Pompe, HIGH);    
   digitalWrite(MAV, HIGH);      
   digitalWrite(MAR, HIGH);     
   
 
}

:warning:

Post mis dans la mauvaise section, on parle anglais dans les forums généraux. ➜ déplacé vers le forum francophone.

Merci de prendre en compte les recommandations listées dans « Les bonnes pratiques du Forum Francophone”

Pour passer d'un code bloquant à un code non bloquant, il faut changer de point de vue : au lieu de se focaliser sur l'enchainement des tâches ou des instructions, il faut se focaliser sur le temps qui passe.
En gros, la principale tâche de ton nouveau code est de mesurer le temps. Et lorsque le temps écoulé arrive à certaines valeurs (que tu as identifiées en amont) alors tu lances des fonctions rapides (et non bloquantes bien sûr).
C'est plus facile à dire qu'à faire : il vaut mieux apprendre avec des cas simples et passer à ton problème lorsque tu as bien compris la philosophie.

J'ai fait un petit tuto ici (il vaut ce qu'il vaut...) :

Bonjour
Merci pour ton aide.
Effectivement la logique semble changer complètement.
Je vais faire des tests mais c'est quand même frustrant car cela fonctionne bien avec 8 secondes et pas avec 80 secondes.
Stéphane

Quel est le type declaré pour temps?

Bonjour,
C'est INT LONG

// ESP robot
int N=72; // nombre de cycle marche avant-marche arrière défaut mettre 70
int long temps;  
_Bool BP=0;

Merci par avance
Stéphane

Ça devrait être un unsigned long
Si vous êtes sur esp8266 ou esp32 ça ne devrait pas être le problème cependant

Postez tout le code et expliquez ce que vous voyez dans le console série

Bonjour Jackson,
Je viens de changer avec unsigned long et effectivement pas de changement.
Ci dessous mon code en entier

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// WiFi
const char *ssid = "******"; // Enter your WiFi name
const char *password = "*********";  // Enter WiFi password

// MQTT Broker
const char *mqtt_broker = "192.168.1.66"; // IP serveur mqtt
const char *mqtt_username = "******";
const char *mqtt_password = "********";
const int mqtt_port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);

// ESP robot
unsigned int N=12; // nombre de cycle marche avant-marche arrière défaut mettre 70
unsigned long temps;  
_Bool BP=0;


#define MAV 0     // D3 sur ESP 8266 Marche Avant 
#define MAR 14    // D5 sur ESP 8266 Marche Arrière
#define Pompe 16  // D0 sur ESP 8266 Moteur pompe
#define LEDON 12  // D6 sur ESP 8266 Led Off
#define LEDOFF 13 // D7 sur ESP 8266 Led On
#define BPMA 15   // D8 sur ESP 8266 Bouton poussoir démarrage


void setup() {
  
  // Set software serial baud to 115200;
  Serial.begin(115200);

  // connecting to a WiFi network
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  //connecting to a mqtt broker
  client.setServer(mqtt_broker, mqtt_port);
  client.setCallback(callback);
  while (!client.connected()) {
      String client_id = "esp8266-client-";
      client_id += String(WiFi.macAddress());
      Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
      if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
          Serial.println("Public emqx mqtt broker connected");
      } else {
          Serial.print("failed with state ");
          Serial.print(client.state());
          delay(2000);
      }
  
  }


    // ESP robot
    pinMode(MAV, OUTPUT);
    pinMode(MAR, OUTPUT);
    pinMode(LEDON, OUTPUT);
    pinMode(LEDOFF, OUTPUT);
    pinMode(Pompe, OUTPUT);
    pinMode(BPMA, INPUT);
    client.publish("ESP_Robot_Piscine/Etat", "0"); 
    client.publish("ESP_Robot_Piscine/Avancement%", "0");
}

void callback(char *topic, byte *payload, unsigned int length) {
  Serial.print("Message arrived in topic: ");
  Serial.println(topic);
  Serial.print("Message:");
  for (unsigned int i = 0; i < length; i++) {
      Serial.print((char) payload[i]);
  }
  Serial.println();
  Serial.println("-----------------------");
}



void loop() {
  client.loop();
  
  BP=digitalRead(BPMA);
  digitalWrite(LEDOFF, HIGH);
  digitalWrite(LEDON, LOW);
  
  if ((BP)==1) {
    Serial.println("**** DEMARRAGE DU CYCLE ****");
    client.publish("ESP_Robot_Piscine/Etat", "1"); 
    digitalWrite(LEDOFF, LOW);
    digitalWrite(LEDON, HIGH); 
    digitalWrite(Pompe, LOW); // Attention commande inversée Low à la place de High
    Serial.println("Pompe en marche");
    delay(6000);  
  
    for (unsigned int i = 1; i <= N; i++) {
               
      digitalWrite(MAV, LOW);  
      digitalWrite(MAR, HIGH);  
      Serial.println("Marche AVANT");
      temps=(random(30000,60000));  // A modifier en fonction taille piscine et si plus fond que paroies
      delay(temps);
         
        // Arret de la pompe 8s pour faire tourner le robot de 90°
        if (i==N/3) {
        digitalWrite(Pompe, HIGH); 
        Serial.println("PAUSE 1 POMPE POUR TOURNER");
        delay(8000);
        digitalWrite(Pompe, LOW);
        }
      
      // Arret de la pompe 8s pour faire tourner le robot de 90°
        if (i==N/2) {
        digitalWrite(Pompe, HIGH); 
        Serial.println("PAUSE 2 POMPE POUR TOURNER");
        delay(8000);
        digitalWrite(Pompe, LOW);
        }
        
      digitalWrite(MAV, HIGH); 
      digitalWrite(MAR, HIGH); 
      delay(500);
           
      digitalWrite(MAV, HIGH); 
      digitalWrite(MAR, LOW);  
      Serial.println("Marche ARRIERE");
      temps=(random(30000,60000));  // A modifier en fonction taille piscine et si plus fond que paroies
      Serial.print(temps/1000);
      Serial.println("sec");  
      delay(temps);      

  
      digitalWrite(MAV, HIGH);  
      digitalWrite(MAR, HIGH);  
      Serial.println("PAUSE"); 
      delay(500);       

      Serial.print("i= ");
      Serial.println(i);
      Serial.print("%= ");
      Serial.print(i*100/N);
      Serial.println("%"); 

      
     
      // Convert the value to a char array
      char Avancement[8];
      dtostrf(i*100/N, 1, 0, Avancement);
      client.publish("ESP_Robot_Piscine/Avancement%", Avancement);
        
    }
  
     Serial.println("**** FIN DU CYCLE ****");
     client.publish("ESP_Robot_Piscine/Etat", "0"); 
     client.publish("ESP_Robot_Piscine/Avancement%", "0");

   
   }
       
   digitalWrite(LEDOFF, HIGH);  
   digitalWrite(LEDON, LOW);    
   digitalWrite(Pompe, HIGH);    
   digitalWrite(MAV, HIGH);      
   digitalWrite(MAR, HIGH);     
   
 
}

Dans le moniteur l'avancement s'affiche correctement (c'est le %)

Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connecting to WiFi..
Connected to the WiFi network
IP address: 
192.168.1.76
The client esp8266-client-BC:DD:C2:25:98:92 connects to the public mqtt broker
Public emqx mqtt broker connected
**** DEMARRAGE DU CYCLE ****
Pompe en marche
Marche AVANT
Marche ARRIERE
34sec
PAUSE
i= 1
%= 8%
Marche AVANT
Marche ARRIERE
51sec
PAUSE
i= 2
%= 16%
Marche AVANT
Marche ARRIERE
54sec

mais dans MQTT explorer il reste à 0

Par contre cela fonctionne si je passe temps à temps=(random(3000,6000));

Merci pour ton aide
Stéphane

Sans doute vous n’appelez client.loop(); pas assez souvent pour gérer correctement la liaison MQTT

Un hack pour tester serait de modifier les appels à delay() en Les remplaçant par un appel d’une fonction perso avec un while sur millis et exécutant client.loop();

void myDelay(unsigned long d) {
  unsigned long t0 = millis();
  while (millis() - t0 < d) client.loop();
}

(Il faut que client soit une variable globale, sinon la rajouter en paramètre par référence lors de l’appel)

Super ca marche !!!
Grand merci pour votre aide.
J'étais en train de m'arracher les cheveux :sweat_smile:

Du coup j'ai créé la fonction myDelay et remplacé dans les deux "delay(temps);"

Par contre je n'ai rien fais de plus pour définir client (je n'ai pas trop compris la remarque sur ce sujet)

Encore merci !!
Stéphane

void myDelay(unsigned long d) {
  unsigned long t0 = millis();
  while (millis() - t0 < d) client.loop();
}

void loop() {
  client.loop();
  
  BP=digitalRead(BPMA);
  digitalWrite(LEDOFF, HIGH);
  digitalWrite(LEDON, LOW);
  
  if ((BP)==1) {
    Serial.println("**** DEMARRAGE DU CYCLE ****");
    client.publish("ESP_Robot_Piscine/Etat", "1"); 
    digitalWrite(LEDOFF, LOW);
    digitalWrite(LEDON, HIGH); 
    digitalWrite(Pompe, LOW); // Attention commande inversée Low à la place de High
    Serial.println("Pompe en marche");
    delay(6000);  
  
    for (unsigned int i = 1; i <= N; i++) {
               
      digitalWrite(MAV, LOW);  
      digitalWrite(MAR, HIGH);  
      Serial.println("Marche AVANT");
      temps=(random(30000,60000));  // A modifier en fonction taille piscine et si plus fond que paroies
      myDelay(temps);

Cool. Bonne nouvelle :wink:

Celui si mérite aussi d’être modifié


    Serial.println("Pompe en marche");
    delay(6000);  // <<===
  

6 secondes c’est long

Dans votre cas c’était une variable globale donc visible de tous les points du code. Si ça avait été une variable locale, il aurait fallu la passer en paramètre de la fonction myDelay

OK merci encore pour votre aide et disponibilité ! :+1:
Bonne soirée
Stéphane

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