------------------

Introduction

Cet article donne un certain nombre d'instructions, sous Windows 10, pour un débutant qui n'a jamais programmé avec un ESP32, voir un ESP8266 ou même un Arduino classique.

Comme cet article commence à interesser quelques lecteurs, je viens de retoucher la partie du script esp32thermometre.ino ci-dessous (améliorations et dernières versions de l'IDE et des librairies.

Les descriptions en fin d'article restent limitées, souvent juste avec le code, et quelques descriptions.
Ensuite j'y ai ajouté mon travail personnel, comme d'afficher des températures sur le LED venant de Raspberry Pis.

J'y inclurai vraisemblablement l'accès via un "serveur" Flask, si je trouve le temps. A consulter:
Python Flask et SQLite pour le Raspberry Pi 3 ou 4 - exemples de communication avec des ESP32 ou ESP8266
et en travail:
Python Web Flask sur un NAS (Synology)

Ayant déjà utilisé un capteur de température 1-Wire DS18B20 de Dallas, au chapitre 18 de mon livre chez Eyrolles, Programmer en Java pour le Raspberry Pi 3, qui touche aussi au langage Python pour tester les composants déposés sur des platines d'essais, il m'est venu à l'idée d'y ajouter, en plus, un petit écran OLED. Ce dernier permettra de visualiser la température ambiante avec aussi, le minimum et le maximum mesurés.

Comme c'est mon premier exercice sérieux sur un ESP32, j'ai pensé que je pourrais partager ici mes expériences, car il y a beaucoup de petits détails et combines. Du maker tout craché et beaucoup de choses à maîtriser pour un débutant qui ne voudrait sans doute pas perdre trop de temps à se casser la tête. L'ESP32 est le succésseur de l'ESP8266. Il ne le remplace pas forcément, car le second par exemple est souvent meilleur marché. Moi-même j'avais commencé avec l'ESP8266 avant de passer avec le MicroPython plus tard (voir ci-dessous). 

Il y a évidemment plein de références sur le Web. Mon intention n'est pas de faire mieux que les autres, mais avec une approche que j'espère un peu plus ludique 

Le matériel

Le Dallas DS18B20, c'est le plus simple. Nous le trouvons partout.

Pour l'ESP32 et l'écran OLED, c'est un peu différent, il y a beaucoup de modèles et de vendeurs. Ce n'est pas du tout comme un Raspberry Pi 3 Model A+ ou un Raspberry Pi 7″ Touch Screen, où il y a juste UN modèle.

 

Préparation avec l'IDE de l'Arduino

Avant de commencer par écrire un sketch par composants, nous allons décrire l'installation des librairies nécessaires pour les deux cas qui finiront en fin d'article dans une application unique.

Depuis que j'ai commencé avec l'Arduino, il y a de nombreuses années, j'ai toujours repris la dernière version de l'IDE de l'Arduino, et créé un répertoire avec sa version.

En travaillant avec différentes cartes, nous pourrions nous retrouver avec un ensemble de librairies qui pourraient nous créer une sérieuse confusion.
Une méthode est d'effacer le répertoire Documents\Arduino et le contenu du répertoire utilisateur\AppData\Local\Arduino15 avant de faire une nouvelle installation.
Le répertoire Documents\Arduino pourrait aussi contenir des librairies et du matériel que nous aimerions effacer, pour être sûr, par exemple une librairie inséré par erreur. Dans ce cas nous pourrions effacer le répertoire concerné et relancer l'IDE.  

Cet IDE se trouve sur le site https://www.arduino.cc/en/main/software. Nous n'utiliserons pas la version Web, mais la version 1.8.9 (version Windows zip) que nous installerons dans un répertoire comme par exemple D:\arduino-1.8.9.
J'ai aussi pris l'habitude d'utiliser un répertoire de travail, par exemple D:\arduinoDataJb où je dépose mes sketches et dans un sous répertoire D:\arduinoData\esp32 pour mon ESP32 décrit ici.   

L'IDE de l'Arduino permet d'écrire des sketches pour des Arduino classiques, mais aussi pour des ESP8266 ou des ESP32. C'est le firmware installé d'origine qui le permet. Si nous désirions utiliser un autre langage comme le MicroPython par exemple, il faudrait installé le firmware approprié (voir mon article MicroPython, NodeMCU ESP8266 et Thonny).

Lorsque nous aurons connecté notre ESP32 au PC, avec un câble USB assez long, l'IDE devrait nous indiquer quel port est utilisé. En cas de doute, nous pourrons utiliser, sous Windows 10, l'explorateur, sur Ce PC, et le menu Gérer, Gestionnaire de périphérique et Ports (COM et LPT). Si aucun COM n'est visible ce peut être un problème de driver USB ou de module dans l'IDE de l'Arduino.

J'ai eu moi-même quelques difficultés avec le port COM1 sur mon PC principal. Je n'ai pas vu immédiatement qu'il était connecté à ma souris:

port COM4

Dans l'IDE de l'Arduino, c'est bien le COM4, qu'il faudra spécifié, même si COM1 est aussi visible sous le menu Outils / Port!

Il est possible d'avoir d'autres soucis, comme décrit dans Failed to connect to ESP32: Timed out waiting for packet header.

Avant de passer à la référence du modèle d'ESP32 utilisé, nous allons montrer et utiliser un premier script de test: espprintest.ino. Ce script devrait fonctionner pour tous les modèles d'Arduino et d'ESP. Il est important de commencer par la vérification de l'interface entre l'IDE et le micro-controlleur via un câble USB. Le script espprintest.ino doit être déposé dans un répertoire espprintest, c'est une nécessité pour l'IDE de l'Arduino:

void setup() {
Serial.begin(9600); //Communication série
}

void loop() {
delay(500);
Serial.println("Print chaque demi-seconde");
}

Pour le débutant en programmation Arduino, le site https://www.arduino.cc/reference/en/ devrait suffire. Ce dernier possède de nombreux exemples.
Le menu Fichier / Ouvert récemment est pratique pour recharger un ancien script. Si arduino.exe est lancé sans fichier, il risque de nous montrer un nouveau sketch vide avec les entrées habituelles setup() et loop().  

Avec le menu Fichier / Préférence, nous découvrirons une ensemble de paramètres comme l'URL de gestionnaire de cartes supplémentaires où nous cliquerons sur le petit icône disquette afin d'introduire les adresses nécessaires à notre travail, pour l'ESP32 ou autres: 
http://arduino.esp8266.com/stable/package_esp8266com_index.json
https://dl.espressif.com/dl/package_esp32_index.json

J'ai laissé la première référence qui pourrait être utilisée pour des ESP8266.

Après avoir indiqué ces trois adresses, il faudra redémarrer l'IDE. Il est bien pratique d'avoir un raccourci au binaire arduino.exe sur le bureau !. 

Nous irons à présent dans le menu Outils, sous Type de cartes et Gestionnaire de cartes afin d'y ajouter le module pour l'ESP32:


Ensuite, à nouveau dans le menu Outils, sous Type de cartes:

Nous indiquerons la carte ESP32 Dev Module et une vitesse de 115200 est raisonnable pour le téléchargement des scripts.
C'est essentiel de faire cette étape avant de pouvoir compiler le code, car il est souvent spécifique au type de carte, comme le WiFi.

Nous utiliserons les deux boutons Vérifier (V) et Téléverser (->) dans la barre supérieure du menu de l'IDE, afin de déposer le script dans notre ESP32:

Le setup() va initialiser la vitesse sur le port série COM utilisé par le câble USB conncté entre le PC rz l'ESP32.

Dans la boucle loop() nous ferons une pause de 500ms avant de continuer d'envoyer notre message qui sera visible sur le moniteur série.
La vérification se fera avec le menu Outils, Moniteur série:

Le message apparaîtra chaque demi-seconde. Il faudra s'assurer que la vitesse sur le barre horizontale en bas est correcte, c'est à dire 9600 baud. Cette dernière correspond Serial.begin(9600) du sketch.

Cette article-ci utilise deux composants, un DS18B20 et un écran OLED. Nous allons commencer par écrire un sketch par composant afin de les vérifier.

Mon modèle d'ESP32

 Il y a une pléthore de modèles d'ESP32. Sur le site The Internet of Things with ESP32 nous trouverons pratiquement tous les modèles existants au moment de l'écriture de cet article. J'ai choisi le NodeMCU-32S d'AI-Thinker. La définition des broches est similaire à ESP-WROOM-32 d'Espressif que nous avons aussi vérifié avec les composants décrits ci-dessous.

Ce schéma repris d'AI-Thinker nous montre les broches de cet ESP32:

Un premier sketch avec le DS18B20

J'ai nommé le sketch suivant esp32testdallas.ino. à déposer dans un répertoire nommé esp32testdallas.
Nous commencerons par l'examiner avant de le compiler, c'est à dire d'y ajouter les librairies requises. 

#include <OneWire.h>
#include <DallasTemperature.h>
#include "SSD1306Wire.h"

//Le fil data sur la broche P15
#define ONE_WIRE_BUS 15

//oneWire instance pour la communication
OneWire oneWire(ONE_WIRE_BUS);
//La réference du capteur de température Dallas
DallasTemperature sensors(&oneWire);

void setup() {
Serial.begin(9600); //Communication série
sensors.begin();
}

void loop() {
delay(2000);

//Avec sensors.requestTemperatures() pour obtenir
//des valeurs sur tous les capteurs du bus oneWire.
Serial.println("Demande de température...");
sensors.requestTemperatures();

Serial.print("Température pour l'index (0): ");
int res = (int)(sensors.getTempCByIndex(0) * 10);
//Calcul avec une décimale
float resf = (float(res))/10;
Serial.println(resf, 1);
}

Les trois include.h doivent être satisfaits. J'y ai déjà inclus le dernier, pas utilisé ici, pour l'écran OLED.
La démarche est toujours le même lorsque qu'on récupère du code pour des composants particuliers, ici le DS18B20.
Il faut chercher ces bibliothèques et les introduire dans l'IDE de l'Arduino.

Nous le faisons avec  le menu Croquis, Inclure une bibliothèque et Gérer les bibliothèques:

Les trois librairies que nous avons besoin sont visibles dans cette image:

  • OneWire by Jim Studt, ...
  • DallasTemperature by MilesBurton, ...
  • ESP8266 and ESP32 Oled Driver for SSD1306 display by Danier Eichhorn, ...

Elles sont faciles à retrouver en indiquant Tout pour le Type, Tout pour le Sujet et par exemple une recherche avec ESP32 OLED.
Il faudra cliquer sur le bouton Installer qui deviendra gris après installation.

Elles devraient être visible dans la liste, si les bibliothèques Arduino ont été régulièrement mise à jour (proposé au démarrage).

Nous avons déjà indiqué précédemment comment effacer une bibliothèque directement dans le répertoire Documents\Arduino  

En l'exécutant, nous devrions obtenir quelque chose comme:

Demande de température...
Température pour l'index (0): 22.1

toutes les 2 secondes. Le second message n'est pas immédiat: le protocole prend un peu de temps, c'est juste visible.
Un simple soufflement de la bouche sur le capteur permet de voir une petite variation. 

Pour vérifier le cas d'erreur, il suffit de retirer le fil de la broche P15, pour obtenir une valeur de -127.0. Celle-ci pourrait être testée par le logiciel pour indiquer une erreur.
L'index 0 est aussi important. Il est possible d'avoir plusieurs DS18B20 connecté sur le même bus.
Nous trouverons une description par exemple dans l'article Interface Multiple DS18B20s with ESP32.

Un second sketch avec le DS18B20

Avec le sketch esp32testdallas2.ino, nous calculons ici le maximum et le minimum de la température mesurée en améliorant le sketch précédant:

#include <OneWire.h>
#include <DallasTemperature.h>
#include "SSD1306Wire.h"

//Le fil data sur la broche P15
#define ONE_WIRE_BUS 15
//oneWire instance pour la communication
OneWire oneWire(ONE_WIRE_BUS);
//La réference du capteur de température Dallas
DallasTemperature sensors(&oneWire);

float temperatureMinimum = 100;
float temperatureMaximum = -100;

void setup() {
Serial.begin(9600); //Communication série
sensors.begin();
}

//Température sur le bus à une position déterminée
//et avec une seule décimale
float temperature(int pos) {
sensors.requestTemperatures();
int res = (int)(sensors.getTempCByIndex(pos) * 10);
return (float(res))/10;
}

void loop() {
delay(2000);
float newTemperature = temperature(0);

if (newTemperature > temperatureMaximum) {
temperatureMaximum = newTemperature;
}

if (newTemperature < temperatureMinimum) {
temperatureMinimum = newTemperature;
}

Serial.print("Temperature actuelle: ");
Serial.println(newTemperature, 1);
Serial.print("Temperature min et max: ");
Serial.print(temperatureMinimum, 1);
Serial.print(" ");
Serial.println(temperatureMaximum, 1);
}

L'instruction Serial.println(temperatureMaximum, 1); va convertir un float avec une décimal en String.

Le résultat devrait se présenter ainsi:

Temperature actuelle: 21.2
Temperature min et max: 21.0 25.1

Un premier sketch avec l'écran OLED

Le sketch sera nommé esp32testoled.ino.  

Avec le premier sketch du capteur Dallas de température, le DS18B20, nous avons déjà inclus la bibliothèque OLED driver qui nous permettra de compiler le sketch qui suit:

#include "SSD1306Wire.h"
//Initialisation de l'OLED display avec la librairie Wire
SSD1306Wire display(0x3c, 21, 18); //SDA et SCK

void setup() {
Serial.begin(9600); //Communication série
display.init();

//display.flipScreenVertically();
display.setFont(ArialMT_Plain_24);
display.clear();
display.setColor(WHITE);
display.display();
}

int val = 1;
void loop() {
delay(2000);
Serial.print("Print chaque deux secondes: ");
Serial.println(val);
val += 1;

display.clear();
display.drawString(0, 0, "Salut chef!");
display.drawString(0, 30, String(val));
display.display();
}

..... 

Il faudrait décrire le code mais une simple lecture devrait suffire.

Le sketch avec l'écran OLED et nos températures

Le sketch sera nommé esp32thermometre.ino

#include <OneWire.h>
#include <DallasTemperature.h>
#include "SSD1306Wire.h"

//Le fil data sur la broche P15
#define ONE_WIRE_BUS 15
//oneWire instance pour la communication
OneWire oneWire(ONE_WIRE_BUS);
//La réference du capteur de température Dallas
DallasTemperature sensors(&oneWire);

float temperatureMinimum = 100;
float temperatureMaximum = -100;

//Initialisation de l'OLED display avec la librairie Wire
SSD1306Wire display(0x3c, 21, 18); //SDA et SCK

void setup() {
  Serial.begin(9600); //Communication série  display.init();
Serial.println("");
Serial.println("Sketch esp32thermometre");
Serial.print("Une mesure: ");
Serial.println(temperature(0));

  display.setFont(ArialMT_Plain_24);
  display.clear();
  display.setColor(WHITE);
  display.display();
  sensors.begin();
}

//Température sur le bus à une position déterminée
//et avec une seule décimale
float temperature(int pos) {
  sensors.requestTemperatures();
  int res = (int)(sensors.getTempCByIndex(pos) * 10);
  return (float(res))/10;
}

int val = 1;
void loop() {
  delay(2000);
  float newTemperature = temperature(0);
  if (newTemperature > temperatureMaximum) {
    temperatureMaximum = newTemperature;
  }
  if (newTemperature < temperatureMinimum) {
    temperatureMinimum = newTemperature;
  }

  display.clear();
  display.drawString(0, 0, String(newTemperature, 1));
  display.drawString(0, 30, String(temperatureMinimum, 1));
  display.drawString(60, 30, String(temperatureMaximum, 1));
  display.display();
}

Avec String(newTemperature, 1), nous avons à nouveau la conversion en String d'un float avec une décimal.

Jolis résultat:

A faire éventuellement: expliquer un peu mieux.

Mi-avril 2020, j'ai révisé cette partie et aussi en la recompilant avec le version 1.8.12 de l'IDE de l'Arduino et celle de 1.0.4 pour la librairie ESP32 d'Espressif Systems.
J'ai ajouté le code:
 void setup() {
   Serial.begin(9600); //Communication série  display.init();
   Serial.println("");
   Serial.println("Sketch esp32thermometre");
   Serial.print("Une mesure: ");
   Serial.println(temperature(0));

qui permet de montrer au démarrage le nom du script, ici esp32thermometre, et d'indiquer la température au démarrage.
Il faudra se connecter avec un câble USB au PC avec l'IDE de l'Arduino et avec un moniteur série sur le bon COM avec cette bonne vitesse de 9600.

Indiquer le nom du script est pratique si on a oublié de noter ce qu'on a fait sur cet ESP ou qu'on en a plusieurs qui sommeille depuis un certain temps (cela m'arrive!).
Indiquer la première température est pratique, pour vérifier si cela fonctionne toujours correctement et qu'un fil n'a pas été déconnecté lors d'un déplacement (typique d'une température -127 retournée).   

Se connecter au réseau WiFi

Le sketch suivant que j'ai nommé esp32WiFi.ino sera utilisé pour installer et vérifier la connexion à notre réseau WiFi. Il faudra indiquer le nom de son routeur WiFi (la variable ssid) et le mot de passe (la variable pwd). 

#include "WiFi.h"
const char* ssid = "...";
const char* pwd = "...";

void setup() {
Serial.begin(9600);
Serial.println("Configuration du WiFi");
WiFi.begin(ssid, pwd);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connexion au WiFi..");
}

Serial.println("Connecté au réseau WiFi");
}

void loop() {
delay(1000);

if (WiFi.status() == WL_CONNECTED) {
Serial.print("Est connecté au réseau avec ");
Serial.println(WiFi.localIP());
}
else {
Serial.println("N'est pas connecté au réseau");
}
}

Nous ferons la vérification avec l'IDE et le menu Outils, Moniteur série.

Sans messages dans la boucle loop() nous ne pourions savoir si la configuration s'est faite correctement, puisque la partie setup() aura peut-être été déjà exécutée.
Un moyen de voir cette première partie est de garder le terminal actif ou/et de presser le bouton RST sur l'ESP32, à droite du connecteur USB.

La partie du loop() sera ainsi présentée, et chaque seconde:

Est connecté au réseau avec 192.168.1.141
Est connecté au réseau avec 192.168.1.141
.....

L'adresse 192.168.1.141 est attribuée par le routeur.

Il est tout à fait possible de consulter la liste des appareils connectés dans notre routeur, avec un interface Web, pour y vérifier qu'une adresse IP a bien été allouée voire la définir comme adresse IP fixe (statique).

Un serveur Web simple

J'ai nommé ce sketch esp32web.ino. Il contient évidemment l'initialisation du WiFi que nous avons vu précédemment.

#include <WiFi.h>
#include <WebServer.h>

const char* ssid = "...";
const char* pwd  = "...";

WebServer server(80);
 
void setup() { 
  Serial.begin(9600);
  Serial.print("Connexion à ");
  Serial.println(ssid);
  WiFi.begin(ssid, pwd);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  //Montre l'adresse IP et démarre le serveur Web
  Serial.println("");
  Serial.println("WiFi connecté!");
  Serial.println("Adresse IP: ");
  Serial.println(WiFi.localIP());

  server.on("/", deal_onConnect);
  server.on("/test", deal_aTest);
  server.on("/temps", deal_temperatures);
  server.onNotFound(deal_notFound);
  
  server.begin();
}

void deal_onConnect() {
  Serial.println("onConnect");
  server.send(200, "text/html", SendHTML("Connect sur root")); 
}

void deal_aTest() {
  Serial.println("aTest");
  server.send(200, "text/html", SendHTML("Juste un test")); 
}

void deal_temperatures() {
  Serial.println("The temperatures");
  server.send(200, "text/html", "C: 20.6 17.8 22.5");
}

void deal_notFound() {
  Serial.println("notFound");
  server.send(200, "text/html", SendHTML("Not found")); 
}

String SendHTML(String content){
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr += "<title>ESP32 Web Server</title>\n";
  ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #4444FF;margin-bottom: 50px;}\n";
  ptr += "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
  ptr += "</style>\n</head>\n";
  ptr += "<body>\n";
  ptr += "<h1>ESP32 Web Server</h1>\n";
  ptr += "<h3>" + content + "</h3>\n";

  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

void loop() {
  server.handleClient();
  delay(1000);
}

Avant de le compiler et de le télécharger, nous ouvrirons déjà la fenêtre du moniteur série, afin de voir s'afficher l'adresse IP.

L'accès se fait avec par exemple http://192.168.1.141/test.

Ce script ne marche pas trop bien, il faut attendre plusieurs secondes avant de pouvoir rafraichir la page ou entrer cette adresse avec un autre explorateur Internet, comme Chrome qui semble donner plus de difficulté.  

L'application complète

Le sketch final sera composé du code pour récupérer la température, la montrer sur l'écran OLED avec le maximum et le minimum, ainsi qu'un accès avec un serveur Web.

J'ai laissé pour l'instant cette partie, pour passer à l'exercice suivant en août 2019:

 

Récupérer des températures d'autres serveurs Web et les présenter sur le display

Le code est fonctionnel sur deux Raspberry Pi avec une implémentation d'un serveur Web en Java. La requête qui suit devrait être facilement implémentable dans un autre langage. Cependant le composant Dallas accessible sur un broche GPIO, doit être programmer dans un langage qui permet de calculer la température ainsi que les minimum et maximum, et ceci intégrer à un serveur Web. Dans mon cas la lecture de la température se fait dans un thread, le serveur Web est aussi dans un thread, et les deux dans une application Java assez complexe avec d'autres capteurs et logiques.    

Un http://192.168.1.135:8000/temps va nous retourner 

C: 20.5 19.8 21.2

C'est suffisament court pour venir sur une ou deux lignes de notre petit display OLED.
A suivre ...

Comme cet article est en travail, toutes questions ou commentaires pour améliorer cet article sont bienvenus: Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.