# Créer sa station météo - partie 1

Je vous avais parlé dans mon dernier article que je souhaitais me remettre à la programmation Arduino ainsi qu'à la programmation Python afin de tester des montages électroniques.

C'est ce que j'ai fait pour créer ma propre station météo et je vais vous en parler dans cet article pour la partie "Programmation Arduino" et dans le prochain pour la partie "Programmation Python" qui sera plus sur de la programmation MicroPython.

Pourquoi rédiger deux articles sur la création d'une station météo ? Lorsque j'ai acheté mon kit électronique, j'avais accès à un lien me permettant de récupérer une archive avec des informations pour connecter les composants entre eux et faire le programme associé. Mais en parcourant la documentation fournie, je me suis rendue compte que ce n'était pas si facile que ça à faire et qu'il n'existait pas de version pour le faire en microPython, d'où l'idée de ces deux articles.

# Matériel nécessaire

Pour faire ma station météo, j'utilise les composants suivants :

  • une carte ESP8266-12E
  • un capteur de température et d'humidité DHT11
  • un capteur de pression BMP180
  • un capteur de lumière BH1750FVI
  • un écran I2C OLED
  • une breadboard et des fils dupont pour faire les connexions entre les différents éléments

Voici la carte des connexions entre la carte ESP8266-12E et les différents capteurs :

ESP8266-12E I2C OLED BH1750FVI BMP180 DHT11
GND GND GND GND GND
3.3V VCC VCC VCC VCC
D3 SDA SDA SDA
D4 SCL SCL SCL
D5 OUT

# Que va faire ce programme ?

Sur l'écran, on va faire un affichage de type "sliders", c'est-à-dire que l'écran va afficher 4 vues différentes qui vont se dérouler les unes à la suite des autres :

  • la date et l'heure,
  • la météo du jour,
  • la météo à 3 jours,
  • les données des capteurs : température, humidité, pression et luminosité

Pour la récupération des informations météo, on utilise l'API d'OpenWeatherMap. Pour cela, il faut se créer un compte afin de se créer une clé d'API que l'on pourra ensuite passer dans les appels que l'on fera dans l'application.

La plupart des exemples que j'ai trouvé utilisaient aussi l'API de ThingSpeak mais je n'avais pas envie de pousser les données lues sur les capteurs vers le Web, je voulais juste les afficher sur l'écran - histoire de réfléchir au code pour afficher correctement les données sur l'écran.

J'ai créé un projet Github qui va contenir tous les fichiers que je vais utiliser dans cet article est le suivant: weatherstation-demo.

# Programmation Arduino

Pour bien commencer, on va configurer Arduino avec tous les éléments dont on a besoin.

# Arduino IDE

L'IDE pour programmer les cartes Arduino et autres est disponible ici. Il vous permettra de coder votre application et de la charger ensuite sur la carte ESP8266 pour tester votre programme après l'avoir compilé.

# Configurer Arduino IDE

On va tout d'abord ajouter la gestion des cartes ESP8266 à Arduino IDE. Pour cela, vous allez dans Fichier->Préférences et ajouter dans URL de gestionnaire de cartes supplémentaires le lien : https://arduino.esp8266.com/stable/package_esp8266com_index.json.

Ajout de la gestion des cartes ESP8266

Une fois l'ajout fait, il suffit de fermer cet écran en cliquant sur OK. On va ensuite dans Outils->Type de cartes->Gestionnaire de carte. Dans la partie recherche, on saisit "esp8266" pour filtrer les résultats et on installe la version "ESP8266 by ESP8266 Community" en cliquant sur le bouton Installer.

Gestionnaire de carte - sélection ESP8266

Quand l'installation est terminée, on peut fermer cet écran en cliquant sur le bouton Fermer.

Si on retourne dans le menu Outils->Type de carte->ESP8266 Boards(2.7.4), on peut maintenant sélectionner la carte que l'on va utiliser dans notre montage NodeMCU 1.0 (ESP-12E module).

On va maintenant choisir le port sur lequel la carte est connectée, en allant dans Outils->Port et là on choisit le port où la carte est connectée (ne pas oublier de la brancher via le câble USB 😉 ).

# Importer le projet weatherstation-demo à Arduino IDE

Après avoir cloné le projet Github weatherstation-demo, on va dans Fichier->Ouvrir pour charger le fichier WeatherStationDemo.ino qui se trouve dans weatherstation-demo/arduino/WeatherStationDemo. Le fichier est chargé dans l'IDE ainsi que les fichiers WeatherStationFonts.h et WeatherStationImage.h qui contiennent les définitions des fonts et images utilisées dans l'affichage des informations sur l'écran OLED.

Chargement du fichier WeatherStationDemo

# Ajouter des librairies à Arduino IDE

Pour ajouter une librairie, on va dans Croquis->Inclure une bibliothèque->Ajouter la bibliothèque .ZIP....

Ajout d'une bibliothèque

On va ajouter les 3 fichiers suivants :

  • weatherstation-demo/arduino/libs/esp8266-weather-station-master.zip
  • weatherstation-demo/arduino/libs/json-streaming-parser-master.zip
  • weatherstation-demo/arduino/libs/esp8266-oled-ssd1306-master.zip

Attention

Lors des tests que j'ai effectué pour rédiger cet article, j'ai quelques erreurs de compilation. Ces erreurs venaient du fait que la librairie esp8266-weather-station-master n'était pas installée dans sa dernière version (2.0.1) ce qui générait des erreurs de fichiers manquants ou en erreur.

Connaître la version d'une librairie

On va aussi ajouter la librairie d'Adafruit Adafruit_BMP085. Pour cela, on va faire Croquis->Inclure une bibliothèque->Gérer les bibliothèques. Comme pour l'ajout de nouvelles cartes, on va chercher les librairies correspondants au capteur "BMP085".

Ajout de la librairie Adafruit_BMP085

On clique sur le bouton "Installer" pour ajouter cette librairie à notre projet. Il est possible qu'un message de dépendances manquantes s'affiche, pour être sûr que tout se passe bien lors de la compilation, on clique sur "Install all" pour avoir aussi les dépendances. Lorsque l'installation est terminée, on n'a plus qu'à cliquer sur le bouton "Fermer" pour fermer cet écran.

# Mise à jour du code

Dans le fichier WeatherStationDemo.ino, il faut mettre à jour les éléments de connexion au Wifi ainsi que la clé d'API pour OpenWeatherMap :

/***************************
 * WIFI Settings
 **************************/
const char* WIFI_SSID = "your_wifi_ssid";
const char* WIFI_PWD = "your_wifi_pwd";
// OpenWeatherMap Settings
// Sign up here to get an API key:
// https://docs.thingpulse.com/how-tos/openweathermap-key/
const boolean IS_METRIC = true;
String OPEN_WEATHER_MAP_APP_ID = "your_openweathermap_app_id";
String OPEN_WEATHER_MAP_LOCATION = "your_location";

# Tester le programme

Pour tester si tout fonctionne bien, on va compiler et charger le programme sur la carte ESP8266. Tout d'abord, on va vérifier que le programme compile en cliquant sur le bouton "Vérifier" dans l'IDE.

Vérifier le programme

Si la vérification est correcte (il n'y pas d'erreur), on va pouvoir le charger sur la carte en cliquant sur le bouton "Téléverser avec un programmateur" dans l'IDE. Attention, cela peut prendre un peu de temps car il y a d'abord la compilation avant de charger le binaire sur la carte.

Téléverser avec un programmateur

# Comprendre le code

Un programme Arduino de base a 2 fonctions :

void setup() {
}
void loop() {
}

Ce programme n'échappe pas à la règle mais avec en plus les définitions de constantes et de variables qui vont être utilisées tout au long du programme :

  • WIFI,
  • DHT11,
  • Atmosphere et capteur de lumière,
  • I2C OLED,
  • intervalle de mise à jour,
  • Time zone (TZ),
  • OpenWeatherMap,
  • OLED display UI

Ensuite, on déclare les prototypes des fonctions qui seront utilisées dans le programme :

void drawProgress(OLEDDisplay *display, int percentage, String label); // affichage d'une barre de proggresion
void updateData(OLEDDisplay *display); // mise à jour des données affichées sur l'écran
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); // affichage de la date et heure
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); // affichage de la météo du jour
void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); // affichage de la météo à 3 jours
void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex); // affichage du détail de la météo
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state); // affichage du bas de page de l'écran avec l'heure et la température
void drawTempIntern(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y); // affichage des informations récupérées via les capteurs
void setReadyForWeatherUpdate(); // pour faire les mises à jour des données

Les affichages changent régulièrement grâce au code suivant :

// Add frames
// this array keeps function pointers to all frames
// frames are the single views that slide from right to left
FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast, drawTempIntern };
int numberOfFrames = 4;
OverlayCallback overlays[] = { drawHeaderOverlay };
int numberOfOverlays = 1;

Je ne vais pas détailler toutes les fonctions du code, je vais juste faire un focus sur 2 fonctions que j'ai trouvé intéressantes.

# Fonctions de dessin

Si on prend, par exemple, la fonction drawCurrentWeather qui permet d'afficher la météo du jour dont voici le code :

void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  display->setFont(ArialMT_Plain_10);
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->drawString(64 + x, 38 + y, currentWeather.description);
  display->setFont(ArialMT_Plain_24);
  display->setTextAlignment(TEXT_ALIGN_LEFT);
  String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "°C" : "°F");
  display->drawString(60 + x, 5 + y, temp);
  display->setFont(Meteocons_Plain_36);
  display->setTextAlignment(TEXT_ALIGN_CENTER);
  display->drawString(32 + x, 0 + y, currentWeather.iconMeteoCon);
}

Dans cette fonction, on peut noter que l'on mélange à la fois l'affichage display-> et la récupération de données String temp =.... L'affichage dans l'écran se fait en 2 temps, d'abord on sélectionne la font ou l'image que l'on va afficher ainsi que l'alignement du texte, et ensuite, on affiche drawString le résultat en donnant la position de départ sur l'écran (x et y) et la donnée à afficher.

# Fonctions de lecture des capteurs

Si on prend, par exemple, la fonction readAtmosphere qui permet de lire la pression atmosphérique du capteur BPM280 dont voici le code :

void readAtmosphere(){
  tempAtom = bmp.readPressure();
  Serial.print("Pressure = ");
  Serial.print(tempAtom);
  Serial.println(" Pascal");
}

Dans cette fonction, on va lire la pression du capteur via l'utilisation de la librairie d'Adafruit que l'on a ajouté au projet. L'avantage de cette librairie est que les données lues sont directement exploitable (elles ont en Pascal) et l'on n'a pas besoin de faire des calculs du genre :

float B = 1 / 5.25588;
float calcAltitude(float p0, float p1, float t) {
  float C = pow((p0 / p1), B) - 1.0;
  return (C * (t + 273.15)) / 0.0065;
}

Merci @Kongduino pour les explications et le code.

# Conclusion

Et voilà, cette première partie est terminée même si elle était déjà un peu longue. Dans la prochaine partie, je décrirai la version faite en MicroPython. En attendant, le code et les librairies sont disponibles sur mon Github weatherstation-demo.

Have fun !