Mega2560 + ESP8266 + MQTT : bug de communication

Bonjour à tous,

J'utilise un Mega2560 avec un esp8266 embarqué afin de lire le relevé d'une sonde pH (partie Mega) et de l'envoyer à l'esp pour la transmettre via wifi sur un broker mqtt (partie esp, en l'occurrence le broker est un mosquitto installé sur une box jeedom).
Cela fonctionne durant quelques minutes voire une heure ou deux, et puis au bout d'un moment je ne reçois plus rien sur mon broker, ou alors des valeurs vides.

Voici le code Mega (je me suis inspiré de quelqu'un l'ayant fait avant moi) :

#include <Wire.h>  // bibliotheque pour sonde ph 
#include <LiquidCrystal_I2C.h> // bibliothèque de l'écran LCD

// Parametrage adresse LCD (ici c'est 0x27) pour un 16 colonnes et 2 lignes.
LiquidCrystal_I2C lcd(0x27, 16, 2);

//Pin sonde PH 
int PowerPh1 = 52; //+
int PowerPh2 = 53; //- (GND)
const int analogInPin = A15;
//Pin Ecran LCD
int PowerLcd1 = 33; //+
int PowerLcd2 = 35;// - (GND)

//declaration des variable du calcul ph 
float calibration = 17.60; // ceci est un coefficient à modifier pour ajuster/calibrer les valeurs ph 
float phValue = 0;
int sensorValue = 0; 
unsigned long int avgValue; 
float b;
int buf[10],temp;


void setup() {
        Serial.begin(115200);  
        Serial3.begin(115200); // port de com avec esp 
        // Initialisation des pins d'alimentation
        pinMode(PowerPh1, OUTPUT);
        pinMode(PowerPh2, OUTPUT);
        pinMode(PowerLcd1, OUTPUT);
        pinMode(PowerLcd2, OUTPUT);
        digitalWrite(PowerPh1, LOW);
        digitalWrite(PowerPh2, LOW);
        digitalWrite(PowerLcd1, LOW);
        digitalWrite(PowerLcd2, LOW);
        //Allumage écran + test
        setPinOut(PowerLcd1,HIGH);
        lcd.init();
        lcd.begin(16,2);
        lcd.clear();
        lcd.backlight();
        lcd.print("Sensor PH");
        delay(2000);
        setPinOut(PowerLcd1,LOW);
}

void loop() 
{ 
   // allume sonde PH
   setPinOut(PowerPh1,HIGH);
   // prend 10 mesure de ph
     for(int i=0;i<10;i++) {
            // appel 10x la fonction de calcul de ph toutes les 1 secondes 
            getPh();
            delay(1000);
     }
   // éteins la sonde ph pour économiser de l'énergie 
   setPinOut(PowerPh1,LOW);
   // affiche la dernière valeur sur l'écran LCD 
   displayLCD();
   phValue = 0;
   
}

void displayLCD(){
        //allumage du LCD
        setPinOut(PowerLcd1,HIGH);
        // initialize the LCD
        lcd.begin(16,2);
        // Allume écran et affiche message
        lcd.backlight();
        lcd.setCursor(0,0);
        lcd.print("Mesure : ");
        lcd.setCursor(0,1);
        lcd.print("Ph = ");
        lcd.print(phValue);
        delay(10000);
        lcd.clear();
        setPinOut(PowerLcd1,LOW);
  }

   
   
void getPh(){
      // boucle qui fait ressortir une moyenne de 10 mesures de ph 
        for(int i=0;i<10;i++) 
       { 
         buf[i]=analogRead(analogInPin);
         delay(30);
       }
       for(int i=0;i<9;i++)
       {
        for(int j=i+1;j<10;j++)
          {
           if(buf[i]>buf[j])
             {
             temp=buf[i];
             buf[i]=buf[j];
             buf[j]=temp;
             }
           }
         }
       avgValue=0;
       for(int i=2;i<8;i++)
       avgValue+=buf[i];
       float pHVol=(float)avgValue*5.0/1024/6;
       float coeff = 1.02; // coefficient d'ajustement perso pour affiner la valeur du ph 
       phValue = coeff * -5.70 * pHVol + calibration;
       // affichage sur le serial 
       Serial.print("Sensor Ph = ");
       Serial.println(phValue);
       
       //envoie des data vers ESP8266 sur Serial 3
       Serial.println("Envoie data vers ESP8266 sur Serial 3 ");
       Serial3.print("$");
       Serial3.print(phValue);
       Serial3.println("$");
         
}
// fonction qui allume et éteint l'écran et la sonde ph avec sortie d'info sur le serial
void setPinOut(int pin , char state ) {
      Serial.print("PIN :" );
      Serial.println(pin);
      Serial.print("STATE :" );
         if (state == LOW ){
            Serial.println("OFF"); 
               }else{
            Serial.println("ON");
            }
      digitalWrite(pin, state); // sets the digital pin 
      delay(500); // laisse du temps à la sonde Ph + écran pour s'allumer et se stabiliser 
    }

et voici le code ESP :

// Bibliothèque wifi
#include <ESP8266WiFi.h>
// Bilbliothèque Mqtt
#include <PubSubClient.h>
 // Entrez ici vos identifant reseau 
const char* ssid = "xxx";
const char* password =  "xxx";
//  Brooker mqtt -> vous devez en créer un sur votre box perso ou se connecter à un brooker gratuit en ligne 
//  ou vous pourrez récupérer vos informations 
const char* mqttServer = "xxx.xxx.xxx.xxx";  //ip du broker
const int mqttPort = xxxx;   // port di broker
const char* mqttUser = "xxx";  // nom user
const char* mqttPassword = "xxx";  // pass user

// initialisation de l'objet wifi et mqtt  
WiFiClient espClient;
PubSubClient client(espClient);

//Adresse de publication perso du topic mqtt ( a modifier avec votre adresse)
#define mqtt_publish_topic_ph "xxx"

// Reception des donnees ph 
const byte numChars = 32;
byte receivedChars_ph[numChars]; // an array to store the received ph data

// boolean pour déclenchement de la publication mqtt si data présente 
boolean newData_ph = false;
 
void setup() {
        Serial.begin(115200);
        // Connection wifi
        WiFi.begin(ssid, password);
        while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.println("Connecting to WiFi...");
        }
        Serial.println("Connected to the WiFi network");
        // Connection broker Mqqt
        client.setServer(mqttServer, mqttPort);
        client.setCallback(callback);
        while (!client.connected()) {
             Serial.println("Connecting to MQTT...");
       
        if (client.connect("ESP8266Client", mqttUser, mqttPassword )) {
            Serial.println("Connected to MQTT");  
              } else {
            Serial.print("failed with state ");
            Serial.print(client.state());
            delay(2000);
          }
        }
        // Publication d'un message test de départ
        client.publish( mqtt_publish_topic_ph , "Hello from ESP8266");
        client.subscribe("esp/test"); // pour tester le message callback (inutilisé dans ce tuto)
  
}
// fonction Mqtt pour récupérer et afficher les messages entrant (inutilisé ici)  
void callback(char* topic, byte* payload, unsigned int length) {
        Serial.print("Message arrived in topic: ");
        Serial.println(topic);
        Serial.print("Message:");
        for (int i = 0; i < length; i++) {
          Serial.print((char)payload[i]);
        }
        Serial.println();
        Serial.println("-----------------------");
 }
 
void loop() {
      reconnect(); // Reconnexion si connexion perdue
      client.loop();  // verification de connection mqtt
      recepetionData(); // ecoute et parsage des données arrivante
      publishValue(); // publication sur le brooker mqtt
  }

void recepetionData() {
      Serial.println("début de receptionData()");
      // boolean qui active ou pas l'enregistrement des data
      static boolean recvInProgress_ph = false;
      static byte ndx = 0;

      //MARQUEURS qui entoure les données ph 
      char startMarker_ph = '$';
      char endMarker_ph = '$';
      // VAR POUR ENREGISTER LES DONNEES
      byte rc;
    
      // Reception des donnees du serial
      while (Serial.available() > 0 )
         {
          rc = Serial.read();
          // ph parsing
          if (recvInProgress_ph == true) {  //boucle pour commencer a entrer les valeur ds la tableau juqu au end marker
          if (rc != endMarker_ph) {
              receivedChars_ph[ndx] = rc;
              ndx++;
              if (ndx >= numChars) {
                     ndx = numChars - 1;
                  }
                }
          else {
            receivedChars_ph[ndx] = '\0'; // terminate the string apres une case blanche
            recvInProgress_ph = false;
            ndx = 0;
            newData_ph = true;
            Serial.println("Data Ph arriving...");
            Serial.print('Ph = ');
            Serial.println(String((char*)receivedChars_ph));
          }
        }
        else if (rc == startMarker_ph) {  //découverte du marqueur et enclenchement de l'enregistrement 
          recvInProgress_ph = true;
        }
      }
      Serial.println("fin de receptionData()");
}

void publishValue() // Publication Mqtt si data présente
{
  Serial.println("début de publishValue()");
    if (newData_ph == true )
    {
      Serial.println("Publishing to broker MQTT");
      client.publish( mqtt_publish_topic_ph , String((char*)receivedChars_ph).c_str() , true );
      newData_ph = false;
    }
Serial.println("fin de publishValue()");
}

void reconnect(){
  if (client.connected()) {
    Serial.println("Connecté MQTT");
  }
  else {
    Serial.println("Déconnecté MQTT");
  }
  while (!client.connected()) {
    Serial.println("Connection au serveur MQTT ...");
    if (client.connect("ESP32Client")) {
      Serial.println("MQTT connecté");
    }
    else {
      Serial.print("echec, code erreur= ");
      Serial.println(client.state());
      Serial.println("nouvel essai dans 2s");
    delay(2000);
    }
  }
}

Voici les logs de mon broker, lorsque ça fonctionne et lorsque ça ne fonctionne pas :

Pour info, le mega affiche directement sur un écran LCD la valeur lue, et elle n'est jamais vide. Donc je pense que le souci vient + de la partie ESP qu'autre chose.
Un peu novice avec Arduino/esp/tout ça, j'avoue que je vois pas trop comment voir d'où vient le souci, peut-être qu'avec le code vous verrez immédiatement quelque chose qui ne va pas ?

Merci de vos retours :slight_smile: bonne journée.

Guillaume.

Salut,

je n'ai pas vraiment le temps de décortiqué ton code, mais je pense qu'il faudrait que tu trace se qu'il se passe au niveau de l'ESP : j'ai l'impression que la boucle de récéption du sérial n'attend pas correctement la fin du message pour l'envoyé ... comme semble le prouver les derniers logs de ton brocker qui recoit des tonnes de données dans la meme seconde.

Ensuite, je pose la question : pourquoi faire simple quand on peut faire compliquer ???
Y a-t-il une raison pour utiliser à la fois le Mega et l'ESP ?
Je veux dire, l'ESP est largement assez puissant pour gérer la sonde tout seul, voir meme beaucoup plus.
La seule chose qui justifierait d'avoir les 2 serait que tu n'ait pas assez d'IO, mais, au vu de ton descriptif, je doute que ce soit le cas :thinking:

A+

Merci pour cette première réponse ^^ j'avoue que je ne sais pas comment tracer l'esp en mode de fonctionnement "normal" en communication avec le mega. Si je branche en usb sur le pc, je peux avoir sur le serial la sortie du Mega, mais pas celle de l'esp (ou alors j'ai pas compris ou ne sais pas comment faire, ce qui est très possible aussi ^^ ).
Ensuite pour répondre à ta question, j'ai suivi le tuto d'un mec qui a fait ça, et qui semblait dire que le mega est nécessaire pour alimenter la sonde ainsi que l'écran LCD (lien ici : https://custom-one.fr/sonde-ph-connectee-arduino-wifi-mqtt/ ). Mais si c'est possible de s'en passer, soit :slight_smile:

Bon, j'ai regardé le blog en question.
Je ne connais pas la carte qu'il utilise mais de ce que j'ai compris, tu ne peux avoir en même temps la com Mega -> ESP et la sortie série de l'ESP : du coup, t'es aveugle de ce qu'il se passe de son coté :frowning:

A nouveau, je ne vois pas l'utilité d'une telle carte :

  • écran LCD : I2C classique
  • Sonde PH : 1 GPIO.

La majorité des ESP sont capables de le faire :smiley:
Le seul truc est de s'assurer que l'alim soit assez puissante pour la sonde mais je doute que ce soit là aussi un pb.

Ceci dit, je suis interessé par le retour que tu pourrais avoir sur cette sonde : je pensais le faire pour ma piscine il y a quelques années, mais j'avais laissé tombé a cause du prix et surtout que la sonde devait etre calibré régulièrement (ca semble toujours le cas) et avait une durée de vie qui ne dépassait pas une année.
Mais j'espère qu'elles se sont améliorées :slight_smile:

Tu penses que je m'embêterais moins à utiliser simplement un esp ? si oui tu saurais me conseiller quoi prendre ? (s'il y a plusieurs modèles d'esp ou autre).

Pour la sonde, je vais simplement me brancher sur la sonde pH que j'ai déjà dans mon local piscine (branchée à une pompe péristaltique de régulation de pH, je vais y mettre un té BNC et me relier dessus).

Espressif a sortie une nouvelle game l'année derniere mais je ne l'ai pas essayé, par contre j'ai mis sur mon site les différents modeles que j'utilise.
Celui qui s'y rapproche le plus de ton méga coté facilité d'utilisation serait le NodeMCU.
Attention, les ESP fonctionnent en 3.3 volts.

Ok merci je vais regarder ça :slight_smile:
Du coup, l'adapter orp/pH 110 (Adaptateur pH/ORP 1130 Phidgets - Capteurs analogiques Phidgets | GO TRONIC) fonctionnant en 4.25 / 5.25 Vcc, j'imagine que l'esp tout seul ne pourra donc pas l'alimenter ? (ce qui explique peut être le besoin de la carte mega ?).

Si tu l'alimente par USB, le 5v est aussi exposé par la borche VU (il faut vérifier sur le model, car sur certains, ces broches sont noté RSV/reserved et je ne sais pas si le 5V est exposé).

Mais en lisant le datasheet, j'ai vu un autre problème : la carte sort une tension analogique et le convertisseur ADC de l'ESP8266 n'est peut-être pas assez précis :thinking: : il faudrait tester.
(je pensais qu'il sortait directement des données numérique comme les DHT, désolé).

De plus, le meme datasheet indique que la température de l'eau influe de manière non négligeable sur le PHP.
Dans mon cas, l'eau de ma piscine oscille entre 15 quand je la met en route jusqu'a 35 au plus fort de l'été. Est aussi ton cas ?

Attention, quelques mises en garde :

La sonde PH est alimentée en 5V. Cela veut dire que le signal de sortie risque d'évoluer entre 0V et 5V.

Alimenté sous 3.3V, l'écran LCD fonctionnera mal (contraste insuffisant). Il lui faut impérativement du 5V. Par contre la communication I2C entre LCD et ESP8266 ne devrait pas poser de soucis.

D'où sors-tu cette info ?
Il faut simplement savoir qu'un pont diviseur est présent sur les cartes ESP8266 afin de réduire la tension d'entrée (0 à 3.3V) pour la rendre acceptable par l'ESP8266 (0 à 1V).

Si l'on prend comme exemple la WEMOS D1 MINI :

Un pont diviseur 220K + 100K est installé entre A0 et entrée ADC. Il suffit d'intercaler une résistance supplémentaire en série avec A0.
Le calcul donne 390K pour le total (220K + R en série). Donc ajouter une R de 170K sur l'entrée A0 devrait convenir.

ESP8266 : 1 seule entrée analogique. L'ESP32 en possède plusieurs.

Dans mon cas l'eau de la piscine oscille entre 0°C en hiver, et 28/29°C au plus fort :wink:
Bon du coup a priori ESP8266 tout seul = nope ^^ si j'ai bien compris.

Ok, si j'ai bien compris tout ça, cela signifie que juste l'ESP c'est un peu léger pour l'alimentation de l'écran + la sonde ?

Ben malheureusement de mes propres tests.
Sur la sonde de mon poulailler, j'ai fait le même genre de montage avec une source externe, et malheureusement j'ai le même genre de fluctuations.

Je n'ai malheureusement pas encore tester les ADC sur l'ESP32, mais il a pleins d'options super intéressantes comme au niveau de l'alimentation avec un arret maitrisé lorsque l'alimentation chute, rendant possible une alimentation par cellule photoelectrique totalement autonome.
Avec l'ESP8266, sans electronique externe, l'ESP reste planté lorsque la tension d'alimentation remonte lentement ...

Ce que tu fais dans ton test est douteux : tu alimentes l'ESP8266 avec un convertisseur DC/DC et tu mesures la tension d'alimentation. Un convertisseur à découpage n'est pas le meilleur moyen d'alimenter sans bruit.

Le problème est que tu alimentes sonde et LCD à l'aide de deux sorties digitales. Or l'ESP8266 sortira du 3.3V sur ses sorties digitales, et ni la sonde ni le LCD ne fonctionneront.

Au moins, ça répond à la question de "pourquoi ne pas juste utiliser l'esp" :slight_smile:

Cela dit mon pb de départ reste entier :frowning:

Mais est-ce vraiment utile d'alimenter comme cela ?
Le montage fonctionne t-il sur batterie ?
Si la réponse est non, alimenter LCD + sonde avec du 5V. N'importe quelle carte ESP8266 propose une broche 5V (appelée 5V USB sur la WEMOS par exemple).

Autre chose :
Il serait utile de savoir comment est alimentée la MEGA, actuellement, et comment est alimenté l'ESP8266.

Actuellement comme préconisé par le tuto duquel je me suis inspiré, j'alimente la Mega par une alim 12V / 1A CC.

Donc, si tu alimentes l'ESP8266 sur la sortie 5V de la MEGA, le courant disponible peut de pas être suffisant.
Un ESP8266 réclame au moins 400mA pour une connexion WIFI, et le régulateur de la MEGA peut très bien entrer en protection thermique si la connexion dure un peu.

On peut en conclure que :

  • l'alimentation 12V avec une carte NodeMCU ou D1 MINI est à exclure. Il faudra opter pour du 5V.
  • le couple MEGA + ESP8266 est un enfer à déboguer.
  • l'auteur de ton tuto s'emmerde à alimenter sonde et LCD avec des pins digitales "pour économiser l'énergie". Avec un bloc secteur on s'en fout. La MEGA à elle seule consomme plus que tout le reste.
1 Like

Arf, super :smiley:

Du coup, vous avez déjà quelques pistes d'optimisation/changement à proposer/suggérer ? ou carrément des trucs qu'il faudrait changer ?