L'ESP8266 et ThingSpeak pour tracer la courbe de décharge d'un accu.


Dans cet article nous allons voir comment établir la courbe de décharge d'un accu en utilisant un ESP8266 et le service ThingSpeak. Pour ceux d'entre vous qui se demandent ce qu'est ThingSpeak, je vous renvois vers l'(excellent) article que j'ai publié sur le sujet ICI



J'entends déjà certain d'entre vous se demander à quoi ça va nous servir en domotique d'avoir la courbe de décharge d'un accu? Si vous en faites partie je dois vous préciser que ce que je souhaite réaliser c'est un montage à base d'un microcontrôleur qui va mesurer et tracer le niveau de tension de l'accu qui l'alimente en fonction du temps. Et si dit comme cela ce n'est toujours pas plus clair, il me reste à préciser que je souhaite me servir de cette courbe pour repérer trois choses. La première est si l'accu présente une chute de tension brutale à partir d'un certain seuil. La seconde est la tension minimale qui permette au microcontrôleur de fonctionner. La troisième est de pouvoir déduire le temps restant avant d'avoir épuisé la charge. Et je suis certain que maintenant vous avez compris que l'objectif final de cette courbe de décharge, sera de nous permettre de réaliser des montages alimentés sur accu: le monde des objets connectés s'ouvrira enfin à nous!








Point de départ




Avant de nous lancer dans les montages électronique et l'écriture de programmes, nous allons faire le point ici sur tout ce que nous devons savoir, avoir et aussi ce que nous voulons obtenir. 





Définir la cible

Quoi ? 

Commençons par définir ce que nous souhaitons obtenir. Comme nous l'avons évoqué en introduction, notre objectif va être de tracer la courbe de décharge de l'accu qui alimente notre microcontrôleur. Et si vous avez lu attentivement l'article sur "Tout connaitre du suivi des charges et tensions avec un microcontrôleur", vous saurez que cette charge va pouvoir se déduire de la tension aux bornes de l'accu. Tension que nous avons appris à mesurer. La courbe que nous allons donc chercher à obtenir est celle de la tension (en ordonnée) par rapport au temps (abscisses). De cette courbe nous pourrons déduire plein de choses qui nous serons très utiles. Comme par exemple:

  • Voir la forme qu'elle présente pour identifier s'il y a une chute brutale de tension vers la fin de la décharge. Identifier le moment de cette chute nous permettra d'alerter d'une "panne seiche" imminente. 
  • Identifier la tension minimale qui permet au microcontrôleur de fonctionner.
  • Identifier combien de temps un accu peut alimenter le montage et ainsi, en connaissons la consommation du microcontrôleur nous pourrons déterminer sa capacité totale (en Ah).
  • Identifier à partir d'un relevé de tension où nous en sommes sur la courbe de décharge (début, fin, milieu ....) et estimer la durée restante. 
  • Et pour finir, le plus important pour moi dans mes projets futurs, cette courbe va nous permettre d'acquérir une expérience qui nous permettra d'optimiser au maximum la consommation des montages autonomes que nous réaliserons à l'avenir.  
Nous verrons ultérieurement toutes ces choses que nous allons pouvoir déduire de cette courbe. Mais si je résume de manière très concrète, notre objectif va donc de lire à intervalle régulier la tension qui alimente le microcontrôleur et de mémoriser cette valeur quelque part. 

Où ? 

Maintenant que nous savons ce que nous voulons faire, la question qui se pose est de savoir où sauvegarder toutes nos données ?
Ici nous n'avons pas du tout pour objectif d'optimiser la consommation électrique. Toutes les débauches d'énergie nous seront donc permises, comme par exemple utiliser une connexion wifi pour envoyer les données. De plus nous avons indiqué que nous souhaitons avoir une courbe sous forme graphique qui nous permettra de réaliser une analyse visuelle. Et pour finir étant donné que ce que nous réalisons est une expérience qui aura une durée de vie limitée, nous souhaitons pouvoir nous appuyer sur des outils existant plutôt que d'investir beaucoup de temps et d'énergie à créer notre propre service. Tous ces arguments m'ont amené de la manière la plus naturelle possible à déduire que le service à utiliser pour mémoriser et visualiser nos données est ThingSpeak


Si ce nom ne vous dit rien, je vous invite à parcourir l'article que j'ai réalisé ICI et qui décrit ce qu'est ThingSpeak en montrant comment l'utiliser afin de tracer une courbe de température avec un NodeMCU. 

Les choses à savoir

Afin d'atteindre notre cible, un certain nombre de connaissances vont être nécessaires. Toutes ont été abordées dans de précédents articles de ce blog:
  • Connaitre et utiliser ThingSpeak avec un ESP8266: ICI.
  • Suivre la tension d'un accu avec un microcontrôleur: ICI.
  • Connaitre et programmer un ESP8266. Pour le NodeMCU c'est ICI. Pour l'ESP01 et ESP01s c'est ICI.
Mais je ne doute pas un instant que vous avez déjà lu tous les articles du "pote âgé" alors passons à la suite ...

Les choses à avoir

Pour suivre la courbe de décharge d'un accu avec un ESP8266 nous allons réaliser un montage le plus simple possible, nous réaliserons ensuite un programme qui mesurera le niveau de tension et se connectera à ThinkSpeak pour mémoriser la donnée. Cette phrase résume à elle seule tout ce qu'il nous faudra rassembler pour notre projet.

Matériel nécessaire pour le montage

Comme matériel nous aurons besoin:
  • ESP8266 soit sous la forme NodeMCU v3 (ESP-12E et driver CH340G en ce qui me concerne), soit sous la forme ESP-01 (ESP-01s pour ma part). Le mieux serait que vous ayez les deux. Vous pouvez vous procurer:
    1. Les NodeMCU v3: sur eBay ICI (autours de 3€ pièce). Sur Amazon ICI (quelques cts de plus mais avec le service Amazon en cas de problème) ou ICI (qq euros plus cher mais avec la livraison sous deux jours en Prime pour les impatients comme moi).
    2. Les ESP01s: sur eBay ICI (moins de 2€ pièce). Sur Amazon ICI ou un lot de 3 (c'est mieux) en livraison rapide ICI.
 

  • Composants électroniques. En ce qui me concerne je ne pense utiliser qu'un condensateur pour stabiliser le courant d'alimentation. Mais j'aurais peut être besoin également d'une résistance 220Ω, ce n'est pas encore sur. Il me faudra aussi peut être une breadboard et des câbles Dupont.  
    1. Pour les câbles et composants je vous conseille de commander un coffret qui vous permettra d'avoir le choix. Il y a CELUI-CI sur eBay ou sur Amazon ICI
    2. Pour les NodeMCU, ils ne vont pas sur une breadboard classique alors j'aime bien en utiliser deux de 170 points comme ICI sur eBay ou ICI sur Amazon. avec un lot de 12 en livraison rapide.  
    3. Comme on a toujours besoin de cables en plus, avec CE kit vous aurez tous les formats en quantité. 

  • Accu ou piles. Impossible de réaliser ce projet sans ce qui est au cœur de tout: l'accu (ou les piles). De mon coté j'utilise les accu LiIon de type 18650 car la tension de 3,7V et leur capacité supérieurs à 2000mAh me semblent bien adaptés. N'étant pas un expert en accu et les arnaques étant nombreuses dans ce domaine, je me contenterai de vous donner CE lien et quelques conseils:
    1. Sur tous les sites et forum sérieux dans le domaine des accus, il est précisé que la technologie actuelle ne permet pas à un accu 18650 de fournir une capacité supérieure à 3400mAh. Donc si vous achetez des 4000 mAh, 5000 mAh voir 9600 mAh il s'agit surement d'un faux qui ne délivrera en réalité qu'au mieux 1000 mAh.
    2. Pour utiliser plus facilement ces accus, je me suis procuré un super chargeur universel ICI ainsi que des boîtiers afin de les utiliser plus facilement dans les montages (ICI)

Prérequis logiciel

En ce qui concerne la partie logicielle, l'objectif est de pouvoir accéder à ThingSpeak, de pouvoir écrire (ou copier) un programme pour l'ESP8266 et le téléverser sur le microcontrôleur.

Si vous avez déjà tout ça sous la main, vous êtes prêt pour la suite.

Si vous n'avez pas de compte ThingSpeak, je vous invite à aller lire le paragraphe intitulé "Créer un compte" dans l'article A la découverte de ThingSpeak avec l'ESP8266 et un capteur de température. Créez vous un compte!

Pour programmer mes microcontrôleurs j'utilise l'IDE Arduino. Si vous ne l'avez pas installé vous pouvez suivre ce tuto ICI. Et si vous souhaitez, comme moi, utiliser un ESP01s plutôt qu'un NodeMCU ESP12e, quand l'IDE aura été installé, vous devrez aller consulter le paragraphe "Programmation" dans mon article dédié à cette carte ICI.

Une fois tout cela fait, vous êtes maintenant prêt pour la suite.








Programmation



Avant de réaliser le montage final, l'ESP8266 devra être programmé. Nous allons donc maintenant écrire ce code et le téléverser dans le microcontrôleur. 



Afin d'étudier au mieux la consommation des différents formats d'ESP8266 dont je dispose, je vais réaliser le montage et le suivi de décharge avec un ESP01s et avec un NodeMCU v3 Lolin. Et comme nous l'avons vu dans l'article précédent (ICI) sur le suivi des tensions avec les ESP8266, l'ESP01s ne permet pas d'utiliser la broche analogique A0. Pour l'ESP01 il faudra donc utiliser la fonction de mesure interne getVCC(). Et pour ne pas avoir deux programmes et deux montages trop différents, j'utiliserai cette même méthode pour le NodeMCU avec toutes les réserves que nous avions indiquées concernant les microcontrôleurs dont l'ADC est relié en entrée à un pont diviseur de tension. 

Préparation du channel ThingSpeak

Pour écrire la partie d'envoie des données vers la plateforme ThingSpeak, il va nous falloir l'identifiant du "channel". Et comme je souhaite faire des tests avec un NodeMCU et un ESP01s je vais avoir besoin de créer deux channels. Pour créer les channels et récupérer les URLs avec les identifiants permettant d'y accéder consultez le paragraphe "Créer un channel" dans l'article ICI. Pour ma part j'ai crée deux channels que j'ai appelé de manière assez logique: 
  1. decharge_18650_esp01
  2. decharge_18650_NodeMCU
création d'un nouveau channel thigspeak

Chaque channel ne contient qu'un seul champ: tension.
Et dans l'onglet "API Keys" on récupère l'URL complète qui permettra d'envoyer les valeurs des tensions que nous mesurerons au fil du temps. Le champs "field1" correspond à tension et il faudra remplacer le "0" par la valeur mesurée: 
https://api.thingspeak.com/update?api_key=J03IWSXSPM9YX69F&field1=0
Une fois nos channels créés nous pouvons passer à la suite.

Algorithme

Tout bon développeur doit réfléchir à l'algorithme qu'il souhaite coder avant de se lancer et c'est ce que je vous propose de faire. Ici le programme sera relativement simple. Dans la fonction "setup()" nous allons seulement initialiser quelques variables et vérifier que le wifi est bien déconnecté. Si vous avez bien lu l'article sur la mesure de tension (ICI) vous vous souvenez surement que nous avions dit que pour fonctionner correctement la fonction "getVcc()" doit être appelée en dehors de toute transmission. Donc nous ne pourrons pas établir la connexion wifi dans le setup. 
La fonction loop fera donc tout le travail. Elle va mesurer la tension interne avec getVcc(). Et pour plus de précision et de stabilité on ne réalisera pas une seule mesures mais plusieurs et on prendra la valeur médiane. Ensuite en fonction du module que nous utilisons nous appliquerons les coefficients correcteurs que nous avons obtenus en suivant la méthodologie décrite dans l'article précédent. La connexion wifi sera alors initialisée puis la donnée envoyée au channel thingspeak correspondant. En fin de fonction loop nous attendrons simplement un temps déterminé en ayant pris soins de déconnecter le wifi. 

Allez maintenant on code ... yes!! 

Le code

Petit programme de test

Quand je commence un projet, je commence toujours par reprendre un petit programme qui me permet tester que tout est bien en place pour commencer à programmer et debugger. Ce programme ne fait qu'afficher un message à l'initialisation de la liaison série et ensuite incrémente un compteur dans la fonction loop avant de l'afficher également en série. Commencer en reprenant ce programme me permet donc: 

  1. De partir sur un fichier qui est déjà bien structuré par rapport au formalisme que j'aime utiliser dans mes programmes.
  2. De lancer un test de compilation pour voir si mon IDE est prêt à fonctionner. 
  3. De lancer un test de téléversement pour contrôler que le microcontrôleur est bien raccordé et que les paramètres de l'IDE sont bien configurés. Notamment il faut penser à sélectionner le bon port COM dans "Outils/Port" et sélectionner le bon type de carte dans "Outils/Type de carte". 
  4. D'afficher des messages dans le moniteur série pour m'assurer que j'arriverai bien à suivre tous mes messages de debug pendant le développement du programme cible. 
Pour résumer, commencer avec ce petit programme qui ne sert pas à grand chose à tout de même beaucoup de vertus et si vous êtes plutôt débutant dans le domaine je vous conseille de vous habituer à suivre cette méthodologie. 

Je vous livre le code de ce petit programme de test:

/*******************************************************************
* Ce programme ne fait qu'afficher un compteur sur la liaison série.
* Il sert à tester que l'environnement de programmation est prêt:
*   - compilation et téléversement d'un sketch.
*   - communication avec la liaison série pour débugger.
*
* Il donne également un cadre clair pour structurer un programme.
*
* Evolutions possible :
*   - Aucune
*
* Versions :
*   v1 : Création
*
* (c) acampeaux@gmail.com
********************************************************************/

/*====================================================================
  * Inclusion des librairies externes
 * ==================================================================*/

// Ici aucun #include nécessaire.

/*====================================================================
  * Définition de constantes (#define) et des variables globales
 * ==================================================================*/
String stNomProgramme = "test_fonctionnement_serial";
String stVersion = "v1.0";

//////////////////////////////constantes relatives à la connexion série
// Fixe la vitesse de communication série.
// Sur ESP8266 je mets 74880 car c'est la vitesse de communication du controleur au boot.
#define SERIAL_BIT_RATE 74880


//////////////////////////////définitions relatives à la boucle loop

//Temps d'attente à la fin de la boucle loop avant de recommencer un cycle
//En millisecondes
#define DELAY_INTER_CYCLES 2000
// Compte le nombre d'itérations
int iNbIteration = 0;

/*====================================================================
  * Fonction setup(): executée une fois au démarrage du microcontroleur.
  * - Ouvre la liaison série.
 * ==================================================================*/
void setup() {

  ////////////////////////////////////////////Variable locales au setup
  String stMessageAccueil = "";

  ///////////////////////////////////Initialisation de la liaison série
  Serial.begin(SERIAL_BIT_RATE);
  delay( 100 );
  stMessageAccueil = stNomProgramme + " - Version: " + stVersion;
  Serial.println( stMessageAccueil );
  Serial.println( "Serial: OK" );
}


/*====================================================================
  * Fonction loop(): executée en boucle.
  * - Incrémente un compteur.
  * - Affiche le nombre d'itération sur la liaison série.
  * - Attends un délai donné.
 * ==================================================================*/
void loop() {

  ///////////////////////////////////Variable locales a la fonction loop
  String stMessageIteration = "Iteration loop number: ";

  ////////////////////////////////////////////Incrément et affichage
  iNbIteration++;
  stMessageIteration = stMessageIteration + String( iNbIteration );
  Serial.println( stMessageIteration );

  ////////////////////////////////////////////Attente avant nouveau cycle
  delay( DELAY_INTER_CYCLES );
}

Une fois compilé et lancé, voici ce que vous devriez voir défiler dans votre moniteur série:

Moniteur série sketch de test

Le programme final

Lorsque ce petit programme de test aura été compilé et fonctionnera correctement vous pourrez écrire le programme cible qui va réaliser l'algorithme que nous avons évoqué ci-dessus.
En ce qui me concerne, j'aime bien faire les choses de manière un peu "compliquée". Vous avez pu le constater rien qu'en regardant mon programme de test ou je me suis "embêté" à définir des constantes, des variables ou à passer par des lignes de codes qui auraient pu être condensées sur une seule ligne. Mais je pars du principe qu'un code doit être beau, lisible, maintenable, réutilisable et aussi qu'en faisant des choses de manière plus compliquée on apprend à exploiter des fonctions et outils performants. Par exemple l'utilisation de la classe "String" dans mon petit programme de test vous montre un outil de traitement des chaines de caractères souple et puissant dans l'environnement de programmation Arduino. Tout ceci pour dire que si vous vous étonnez de la manière dont j'ai écrit le code du programme final, ce n'est que le fruit d'une démarche volontaire de ma part. 

Je vous livre le code avec tous les commentaires et mes traces de DEBUG:

/*******************************************************************
* Ce programme mesure la tension interne du microcontrôleur et l'envois
* sur un channel ThingSpeak pour en tracer l'évolution dans le temps.
* Il a été écrit pour ESP8266. Il pourra fonctionner sur un ESP01/ESP01s
* ou un NodeMCU ESP12e. Il faudra simplement changer la valeur du coefficient
* correcteur de tension en tout début de programme.
*
* Évolutions possible :
*   - Aucune pour le moment.
*
* Versions :
*   v1 - 24/08/2019: Création
*
* (c) acampeaux@gmail.com
********************************************************************/

/*====================================================================
 * Définit le coefficient correcteur de tension qui sera appliqué au résultat
 * de la fonction getVcc. Ce coefficient n'est pas le même sur un ESP01 ou
 * un NodeMCU ESP12e. Il s'agit d'un nombre réél. Si les coefficients que j'utilise
 * ne sont pas corrects dans votre contexte alors il faudra les échantilloner
 * vous meme en suivant les directive de l'article:
 * https://framboiseaupotager.blogspot.com/2019/07/tout-connaitre-du-suivi-des-charges-et.html
 * ==================================================================*/
#define COEF_GETVCC 1.42 //Sur ESP01 compiler avec 1.07
#define DEBUG //Il faudra commenter cette ligne pour compiler sans les traces.

/*====================================================================
  * Inclusion des librairies externes
 * ==================================================================*/
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

/*====================================================================
 * Place le convertisseur ADC dans un mode de lecture de la tension interne.
 * Les broches analogiques doivent être libres et ne pourront être utilisées
 * ==================================================================*/
ADC_MODE(ADC_VCC);


/*====================================================================
  * Définition de constantes (#define) et des variables globales
 * ==================================================================*/
String stNomProgramme = "courbe_decharge_thingspeak";
String stVersion = "v1.0";

//////////////////////////////constantes relatives à la connexion série
/* Fixe la vitesse de communication série.
  Sur ESP8266 je mets 74880 car c'est la vitesse de communication du controleur au boot.*/
#define SERIAL_BIT_RATE 74880


//////////////////////////////définitions relatives à la boucle loop
/* Temps d'attente à la fin de la boucle loop avant de recommencer un cycle
En millisecondes */
#define DELAY_INTER_CYCLES 10000
/* Compte le nombre d'itérations */
int iNbIteration = 0;

/* Pour calculer une valeur médianne de la tension parmis des mesures faites à
 *  intervalles donnés. Le nombre de valeurs doit etre supérieur à 3 sinon cela ne fonctionne pas.
 *  Il est conseillé de prendre un nombre impaire.
 */
#define MESURE_DELAIS 50
#define NB_VAL  11
int tiMesures[ NB_VAL ];

////////////////////////////////////////////////////// Constantes et variable relatives au wifi
// Temps d'attente en seconde pour se connecter au wifi
#define MAX_TIME_WAIT_WIFI 60

// SSID et identifiants de connexion au Wifi de votre routeur internet.
const char* sSsid = "framboise";
const char* sPassword = "aupotager";
const char* sHostname ="esp";

////////////////////////////////////////////////////// Variables relatives à ThingSpeak
String osThinkSpeakUrl = "api.thingspeak.com";
int iThinkSpeakPort = 80;
String osTSKeyChannel = "????"; //entrer votre clé ThinkSpeak
int iTSFieldNumber = 3;

HTTPClient oThinkSpeakClient;

/*====================================================================
  * Fonction setup(): executée une fois au démarrage du microcontroleur.
  * - Ouvre la liaison série.
 * ==================================================================*/
void setup() {

  ////////////////////////////////////////////Variable locales au setup
  String stMessageAccueil = "";

  ///////////////////////////////////Initialisation de la liaison série
  Serial.begin(SERIAL_BIT_RATE);
  delay( 100 );
  stMessageAccueil = stNomProgramme + " - Version: " + stVersion;
  Serial.println( "" ); //Saute de ligne.
  Serial.println( stMessageAccueil );
  Serial.println( "Serial: OK" );
}


/*====================================================================
  * Fonction loop(): executée en boucle.
  * - Realise des mesures de la tension interne
  * - Calcul la valeur médiane
  * - Connexion wifi et envois vers ThingSpeak.
  * - Déconnexion et attente.
 * ==================================================================*/
void loop() {

  ////////////////////////////////////////////////////////////////////////
  /////////////////////////////////////Variable locales a la fonction loop

  ////////////////////////////////////////////////////////////////////////
  //////////////////////////////On s'assure que le Wifi est bien déconnecté
  int iWifiStatus = WiFi.status();
  int iWifiMode = WiFi.getMode();

#ifdef DEBUG
  Serial.printf( "\n-----------> Debut de boucle loop.\n" );
  vCheckWifiStatus( iWifiStatus, iWifiMode );
#endif

//Deconnecte le wifi s'il ne l'est pas pour utiliser getVcc()
vCheckWifiDisconnected();

 ////////////////////////////////////////////////////////////////////////
 //////////// realise le nb de mesures demandees avec delais entre chaque
  for ( int iCompteur = 0; iCompteur < NB_VAL; iCompteur++ ){
    /* Lecture de la tension en ms */
    tiMesures[ iCompteur ] = ESP.getVcc();
    delay( MESURE_DELAIS );
  }

  /* Classe le tableau */
  for (int i = 0; i < NB_VAL; i++)
    for (int j = 0; j < NB_VAL; j++){
      if ( tiMesures[ i ] > tiMesures[ j ]){
        int iMem = tiMesures[ i ];
        tiMesures[ i ] = tiMesures[ j ];
        tiMesures[ j ] = iMem;
      }
    }

  /* recherche la médiane en prennant la valeur centrale du tableau*/
  int iMediane = tiMesures[ int( ( NB_VAL / 2.0 ) + 0.5 ) - 1 ];

  /* Applique le coefficient correcteur dont la valeur est fonction du type d'ESP */
  float fResultat = float( iMediane ) * COEF_GETVCC / 1000;
  char szResultat[11];
  dtostrf( fResultat, 0, 2, szResultat);
  iNbIteration++;

#ifdef DEBUG
  Serial.println( String("Iteration no: ") + iNbIteration + " Valeur Mediane: " + \
    iMediane + " Tension resultante: " + szResultat );
#endif

  ////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////Connexion Wifi
  WiFi.begin( sSsid, sPassword );

#ifdef DEBUG
  Serial.printf( "Connecting WiFi: SSID=%s PWD=%s ", sSsid, sPassword  );
#endif

int iNbSec = 0;
  while (WiFi.status() != WL_CONNECTED ){
  delay( 1000 );
  iNbSec++; 
#ifdef DEBUG
  Serial.print( "." );
#endif 
  if ( iNbSec >= MAX_TIME_WAIT_WIFI ) {
#ifdef DEBUG
  Serial.printf( "\nDelais de connexion de %d secondes depasse -> restart\n", MAX_TIME_WAIT_WIFI );
#endif   
  // Si on dépasse le délais de connexion on réalise un restart. Pour que la fonction "restart"
  //  fonctionne l'ESP doit avoir été resété une première fois manuellement (avec un reset ou
  //  avec un arret d'alimentation électrique.
    ESP.restart();
  }
 }

#ifdef DEBUG
  Serial.printf( "\n-> Wifi connected in %d seconds\n", iNbSec );
  vCheckWifiStatus( WiFi.status(), WiFi.getMode() );

  String stRes = "Connected to : " + String( sSsid ) + "\nAdresse IP : ";
  stRes += WiFi.localIP().toString() ; //Type IPAddress = tableau de 4 entiers.
  Serial.println( stRes );
#endif

  ////////////////////////////////////////////////////////////////////////
  ///////////////////////////////Envois des données à ThingSpeak
  int iRes = iEnvoiThingSpeak( iTSFieldNumber, fResultat );
#ifdef DEBUG 
  Serial.printf( "Retour iEnvoiThingSpeak = %d\n", iRes );
#endif 

  ////////////////////////////////////////////////////////////////////////
  ///////////////////////////////Déconnexion et attente avant nouveau cycle
  vCheckWifiDisconnected();
#ifdef DEBUG 
  Serial.printf( "-----------> Fin de boucle loop.\n" );
#endif 
  delay( DELAY_INTER_CYCLES );
}


/*====================================================================
  * Fonction vCheckWifiStatus(iWifiStatus, iWifiM):
  * - Affiche un message texte comprehensible correspond
  *   au status et au mode du wifi
 * ==================================================================*/
void vCheckWifiStatus( int iWifiStatus, int iWifiMode ){

    //On va afficher un message fonction du status wifi
    Serial.printf("Connection status: %d\n", iWifiStatus );
    switch ( iWifiStatus ) {
      case WL_DISCONNECTED: { //Valeur 6
        Serial.printf("-> Wifi disconnected.\n" );break;}
      case WL_IDLE_STATUS: { //Valeur 0
        Serial.printf("-> Wifi in process of changing.\n" );break;}
      case WL_NO_SSID_AVAIL: { //Valeur 1
        Serial.printf("-> SSID (%s) cannot be reached.\n", sSsid );break;}
      case WL_CONNECTED: { //Valeur 3
        Serial.printf("-> Wifi connection is established.\n" );break;}   
      case WL_CONNECT_FAILED: { //Valeur 4
        Serial.printf("-> password (%s) is incorrect.\n", sPassword );break;}                 
      default: {
          Serial.printf("-> Status Wifi: inconnu (%d)\n", iWifiStatus );
        }
    }

    switch( iWifiMode) {
      case WIFI_OFF: { //Valeur 0
         Serial.println( "-> Mode Wifi OFF" );break;
      }
      case WIFI_STA: { //Valeur 1
        Serial.println( "-> Mode Wifi WIFI_STA" );break;
      }
      case WIFI_AP: { //Valeur 2
        Serial.println( "-> Mode Wifi WIFI_AP" ); break;
      }
      case WIFI_AP_STA: { //Valeur 3
        Serial.println( "->Mode Wifi WIFI_AP_STA" ); break;
      }
      default: { //Valeur inconnue
        Serial.printf( "Mode (%d) inconnu\n", iWifiMode );
      }
    }
  }

/*====================================================================
  * Fonction vCheckWifiDisconnected()
  * - Deconnecte le wifi s'il ne l'est pas.
 * ==================================================================*/
void vCheckWifiDisconnected(){

  //Si le wifi n'est pas déconnecté on déconnecte
  if ( ( WiFi.status() != WL_DISCONNECTED ) or ( WiFi.getMode() != WIFI_OFF ) ){
#ifdef DEBUG
  Serial.print( "Deconnexion wifi" );
#endif
    WiFi.disconnect( true );
    WiFi.mode( WIFI_OFF );
  while ( ( WiFi.status() != WL_DISCONNECTED ) or ( WiFi.getMode()!= WIFI_OFF ) ){
#ifdef DEBUG 
    Serial.print( "." );
#endif 
    delay( 500 );
  }
#ifdef DEBUG
  Serial.println( "." );
#endif
  }
}

/*====================================================================
  * Fonction iEnvoiThingSpeak( int iField, float fValue )
  * - Envois la donnes fValue a ThingSpeak dans le champs no iField
 * ==================================================================*/
 int iEnvoiThingSpeak(int iField, float fValue){

    int iRes = 0;
    String osUrl = "/update?api_key=" + osTSKeyChannel + "&field" + String( iField ) + "=" + String( fValue );

#ifdef DEBUG 
  Serial.println( "-> Envois a ThingSpeak: " + osUrl );
#endif
    oThinkSpeakClient.begin( osThinkSpeakUrl, iThinkSpeakPort, osUrl );
 
    int iHttpCode = oThinkSpeakClient.GET();
 
    if ( iHttpCode ){
      if ( iHttpCode == 200 ){
#ifdef DEBUG     
        String osPayload = oThinkSpeakClient.getString();
        Serial.print( "oThinkSpeakClient response: " );
        Serial.println( osPayload );
#endif     
        iRes = 0;
      } else {
#ifdef DEBUG         
        String osPayload = oThinkSpeakClient.getString();
        Serial.print( "oThinkSpeakClient response error: " );
        Serial.println( osPayload );
        Serial.print( "Adresse IP ESP : " );
        Serial.println( WiFi.localIP().toString() );
        Serial.print( "iHttpCode : " );
        Serial.println( iHttpCode );
#endif     
        iRes = 1;
      }
    } else {
#ifdef DEBUG       
      Serial.println( "oThinkSpeakClient not response" );
#endif   
      iRes = 2;
     }
    oThinkSpeakClient.end();
    return iRes;
 }

Les particularités de ce programme

A vrai dire, pour une fois je ne me suis pas foulé pour écrire ce programme et pas mal d'améliorations sont faisables.
Par exemple, en début de programme on trouve deux #define à modifier en fonction de votre contexte. J'aurais pu (du) en ajouter d'autres pour ne pas devoir parcourir toute la liste des variables si on souhaite personnaliser encore plus le code. Notamment j'aurais du mettre l'identifiant du channel ThingSpeak à ce niveau.
Au moment de la déclaration des valeurs utilisées pour la connexion Wifi je persiste à définir un "Hostname" bien que pour le moment cela ne sert à rien.
Dans ce programme j'ai décidé de réaliser la mesure de la tension en m'assurant que le wifi était déconnecté. Je fais cela car, comme nous l'avons vu dans l'article précédent, la fonction getVcc() est documenté pour ne pas fonctionner durant des transmissions wifi. Je pensais également pouvoir économiser un peu en consommation si je connectais le wifi juste au moment ou je souhaite l'utiliser. Mais au final j'arrive à d'autres conclusions:
  1. Je ne constate pas une diminution de la consommation si je déconnecte le wifi. Ce serait peut être même le contraire car un connexion semble fortement consommatrice en énergie. Et réaliser la connexion toute les 10 secondes consomme autant que de se connecter dans le setup et de laisser la liaison active même quand elle n'est pas utilisée. 
  2. Je ne constate pas non plus de dysfonctionnement de la fonction getVcc lorsque la connexion est active. Par contre, j'observe au multimètre une baisse de tension au moment où l'ESP va réaliser l'appel HTTP vers ThingSpeak. J'en déduis donc que ce serait à ce moment là que la mesure faite par getVcc() ne serait pas fiable. Comme le programme travaille de manière séquentielle, ici cela ne peut pas arriver. 
J'ai donc réalisé une version remaniée de ce programme pour améliorer tout ça. Et pour m'amuser j'ai réalisé un montage à base de DHT11 qui va mesurer la température et l'humidité. Ce programme va donc envoyer toutes ces données à ThningSpeak. Et là je me dis que je viens de réaliser mon premier objet connecté ... dont l'autonomie sera de 3 jours ... oui ok il y a encore un peu de boulot. J'ai mis le code de ce programme ICI.
Une dernière remarque concernant la fonction de reset logiciel: ESP.restart(). Elle ne fonctionnera que si l'ESP a déjà été restarté manuellement une fois. Si vous téléversez votre sketch et que vous laissez le programme s'exécuter dans avoir resété le microcontrôleur, ce dernier va se figer à l'appel de la fonction. 









Montages, résultats et conclusions

Nous voici déjà arrivé au dernière chapitre de cet article. Une fois le code créé et téléversé, il ne nous reste plus qu'a voir les montages électroniques que nous allons devoir réaliser. Nous pourrons ensuite laisser notre accu se décharger et la courbe se dessiner sur ThingSpeak. Nous pourrons voir quelles conclusions nous allons tirer de ces courbes et de tout ce travail que nous venons de réaliser. Pour finir, le dernier paragraphe de ce chapitre réserve un petit bonus! Comme je l'ai évoqué plus haut, j'ai détourné un peu l'objectif de cet article et pour m'amuser j'ai réalisé mon premier objet connecté qui, en plus de suivre la tension, va suivre la température et l'hygrométrie de la pièce! Sympa! 

Assemblage du matériel

J'ai réalisé des tests sur deux montages différents:
  • Le premier autour d'un NodeMCU ESP12e
  • Le second en utilisant un ESP01s.

Montage pour NodeMCU 

Le NodeMCU embarquant un régulateur de tension à l'entrée de sa broche VIN, le montage à réaliser est ultra simple. En réalité il n'y en a pas vraiment car il s'agit uniquement d'alimenter le microcontrôleur avec l'accu 18650. Au tout début de l'expérience, je me suis amusé à placer en coupure mon magnifique multimètre (le JANISA PM18C qui était commercialisé par Meterk quand je l'ai acheté et que je ne peux que vous conseiller) afin de mesurer la consommation moyenne du circuit. Le montage utilise deux breadboard 170 points pour tenir le MCU, quelques câbles Dupont et l'accu dans son boitier. Je n'ai pas fait de schémas tant c'est simple, juste une petite photo. 

Montage autour du NodeMCU avec multimètre

La consommation électrique varie peu. Elle se situe entre 69 mAh et 70 mAh.
Lorsque j'ai enlevé le multimètre le montage se résume à cela: 

Montage autour du NodeMCU sans multimètre

Le + sur VIN et le - sur GND. J'ai aussi ajouté un condensateur (de CE genre) en parallèle et j'ai constaté que cela stabilisait légèrement la tension, surtout dans les niveaux les plus bas. Donc si vous en avez sous la main, surtout n'hésitez pas à en placer un.

Montage pour l'ESP01s

L'ESP01s est quasiment identique à l'ESP01. Les différences entre les deux versions (ESP-01 vs ESP-01S) sont les suivantes :
  • PCB bleu vs PCB noir 
  • flash de 512kB vs flash de 1MB 
  • LED d'alimentation rouge vs  pas de LED d'alimentation.
  • LED bleue sur TX vs LED bleue sur GPIO2 (bas = activé)
  • Meilleur signal WiFi sur le 01S
  • Vitesse de la liaison série : 9600 bauds sur le 01 et 115200 sur le 01S
Dans cet article les montages comme le programme fonctionneront de la même manière sur les deux versions d'ESP01.

Contrairement au montage avec le NodeMCU, celui-ci va nécessiter de connecter quelques composants supplémentaires:
Une diode 1N4007 de CE coffret pour faire abaisser un peu la tension d'entrée si vous craignez d'abimer votre bel ESP. L'ESP01 ne disposant pas d'un régulateur de tension comme le NodeMCU cette diode va provoquer une baisse de tension de 0,6V environ lorsque l'ESP est en charge. Pour ma part, je prendrai le risque de ne pas utiliser cette diode. L'ESP01 devrait supporter la tension de 4,2V de l'accu chargé au maximum.
Un condensateur 1000 µF pour réguler la tension appliquée à VIN et ainsi espérer avoir des mesures plus stables. Je pense qu'un autre type de condensateur peut aussi fonctionner.


Montage sur un accu d'un ESP01s

Résultats et conclusions

Avec le NodeMCU

Ma première série de test avec le montage NodeMCU m'a permis d’obtenir la courbe suivante:


Le NodeMCU a fonctionné de 17h à 16h le lendemain. Soit environ 23 heures. 
Durant les 5 premières heures, la tension est longtemps restée autours de 3,85V. Ceci s'explique par la présence du régulateur de tension qui abaisse à ce niveau toute tension supérieure (sur VIN). L'accu 18650 au début de l'essai était chargé à 4,2V. Durant les 5 premières heures la tension est donc passée de 4,2V à 3,85V. Mais l'ESP n'a mesuré qu'une tension de 3,85V qui est la tension donnée par le régulateur. 
Ensuite la tension a commencé à baisser. La pente de la courbe, donc la chute de tension, est de plus en plus rapide. Le NodeMCU s'arrête à 3,2V.
D'après mes mesures, la consommation électrique étant de 70 mAh, les 23 heures de fonctionnement ont donc consommé 1610 mA. Mes accus étant donnés pour 2400 mAh, si l'on suit cette courbe de décharge, on peu calculer que ces 2400 mA auront été délivré lorsque l'accu aura atteint une tension de 2,77V. Ceci est cohérent compte tenu du fait qu'il ne faut pas dépasser 2,5V pour ne pas risquer de détruire l'accu. 

Mes conclusions sont donc:
  • Le NodeMCU fonctionne de manière stable avec le wifi jusqu'à une tension de 3,2V
  • Mon accu est capable de délivrer 1600 mAh utiles pour le NodeMCU. 
  • Sans notion d'économie d'énergie le NodeMCU fonctionnera 23h en continue avec une émission en wifi toute les 10s. 
Ceux d'entre vous qui lisent avec attention mes articles (merci maman), auront peut être remarqué que dans le précédent, lorsque nous avons réalisé des tableaux de mesure de la tension interne, nous avions pu tracer des résultats jusqu'à 2,65V. Alors pourquoi dans ce cas, le microcontrôleur s'arrête à 3,2V ? Il y a deux explications qui me viennent à l'esprit. La première est qu'à la différence des tests réalisés dans l'article précédent, ici nous utilisons le wifi qui nécessite toujours un apport de puissance lors de la connexion et l’émission. Ce besoin en énergie peut faire chuter la tension et rendre instable le microcontrôleur lorsque son alimentation est basse. La seconde, c'est qu'au démarrage du NodeMCU on constate une chute importante de tension durant quelques instants. Cette chute est de l'ordre de 0,4V. Dans l'article précédent le NodeMCU n'avait jamais eu besoin de rebooter. Mais ici cela c'est produit lorsque la tension est arrivée à 3,2V. Et la chute de tension due au reboot à fait passer le seuil d'instabilité, si bien que le microcontrôleur n'a jamais pu reprendre son fonctionnement normal. 

J'ai réalisé une seconde série de mesure en utilisant le même montage avec le NodeMCU. Mais cette fois en compilant le programme sans le mode DEBUG. C'est à dire en supprimant toutes les traces envoyées sur la sortie série qui de toute manière n'est pas raccordée. On obtient la courbe suivante:


Le microcontrôleur a fonctionné de 20h30 jusqu'à 18h00, soit environ 21h30, en passant d'une tension initiale de 3,86V à 3,28V. En mesurant la consommation j'ai constaté une moyenne de 70 mAh. Ce qui est identique au test précédent. Bien que je ne reçoive plus de données sur ThingSpeak, j'ai laissé le montage en place encore quelques heures et j'ai mesuré la tension de l'accu avec mon multimètre. J'ai constaté une tension de 2,6V.

Conclusions de ce second test:
  • La suppression des traces sur la sortie série n'a pas montré une baisse de la consommation. 
  • Même lorsque le montage ne fonctionne plus, la tension continue de baisser. 

Avec l'ESP01s

Avec l'ESP01s la première mesure a été prise vers 22h avec un tension d'accu de 4,03V. L'ESP a émis jusqu'au sur-lendemain à 1h du matin. Soit un fonctionnement de 27h. La tension finale était de 1,94V. J'obtiens la courbe ci-dessous:

Décharge accu 18650 avec ESP01s série 1
Conclusions de ce second test:

  • On constate que l'ESP01s est capable de descendre en tension plus bas qu'avec un NodeMCU. Ceci lui permet donc, à consommation quasiment identique, du durer un peu plus longtemps. 

Bonus: capteur de température

Ne souhaitant pas m'arrêter sur ma lancée, j'ai eu envie avant de conclure cet article d'essayer de reprendre mon montage avec l'ESP01s et d'y ajouter un capteur de température DHT11, ainsi qu'une LED contrôlée par la broche GPIO00.

De plus, j'ai souhaité optimiser plusieurs choses: 

  • La connexion wifi qui se fait désormais dans le setup et qui n'est plus coupée à chaque connexion. 
  • Le temps d'attente entre chaque mesure qui passe de 10 secondes à une minute. 
  • Le code a été amélioré pour le rendre plus facilement personnalisable.


L'algorithme est simple: 

  • On initialise les broches, la liaison série et la connexion wifi dans le setup. 
  • Dans la boucle "loop": 
    • On mesure le niveau de tension. 
    • On interroge le DHT11 pour avoir la température et l'hydrométrie ambiante.
    • On envois le tout à ThnigSpeak et pendant l'envois la LED s'allume. 
    • On attend le temps demandé.


ESP01s sur accu 18650 capteur de température 

Vous pourrez trouver le programme complet ICI.

Le test a démarré le 29/08 à 23h00 avec une tension d'accu de 4,1V. Il a fonctionné durant 37h et la tension était seulement à 3,4V le 31/08 à 12h00. Pour finaliser le test et avoir toute la courbe de décharge j'ai fais en sorte que l'accu se décharge plus rapidement sur la fin.

Voici deux des courbes que j'obtiens: la tension et la température (on distingue bien les cycles jour/nuit).



En conclusion de cet article, nous avons pu suivre la consommation électrique de ESP raccordés à un accu 18650. Nous avons pu estimer la quantité d’électricité dont nous disposions, nous avons repéré les seuils bas de tension jusqu’où les microcontrôleurs vont fonctionner, nous avons pu valider qu'il est possible de mesurer la tension et d'utiliser le wifi, nous avons pu également construire notre premier objet connecté qui a fonctionné sur 3 jours. Nous avons vu comment organiser le code de nos programmes. Au final, entre cet article et le précédent, nous avons désormais acquis toutes les connaissances pour nous lancer dans l'ultime étape qui nous permettra de construire nos propres objets connectés: l'optimisation de la consommation! Et cette fois j'espère que nous arriverons à transformer ces 3 jours en 3 mois!





Soutenez la blogoculture ...

Le plus simplement du monde, si vous avez un achat à faire sur Amazon, accédez au site à partir de ce lien (que vous pouvez ajouter dans vos favoris)https://amzn.to/2nbe4sm



Merci

Commentaires