Construire une station météo sans fil Arduino fiable
Dans ce tutoriel, nous allons apprendre à réaliser une station météo sans fil basée sur Arduino. Vous pouvez regarder la vidéo suivante ou lire le tutoriel écrit ci-dessous. La température et l'humidité extérieures sont mesurées à l'aide d'un capteur DHT22, et ces données sont envoyées sans fil vers l'unité intérieure via des modules transcepteurs NRF24L01. Au niveau de l'unité intérieure, un autre capteur DHT22 mesure la température et l'humidité intérieures, ainsi qu'un module horloge temps réel DS3231 qui conserve l'heure même si l'Arduino perd son alimentation. Toutes ces données sont affichées sur un écran OLED 0,96". Examinons le schéma de câblage et le fonctionnement de ce projet. Notez que j'ai déjà des tutoriels détaillés sur le fonctionnement de chacun de ces modules, vous pouvez les consulter : Tutoriel NRF24L01, Tutoriel DHT22, Tutoriel DS3231. Vous pouvez vous procurer les composants nécessaires pour ce projet via les liens ci-dessous : Le module horloge temps réel et l'écran OLED utilisent tous deux le protocole I2C pour communiquer avec l'Arduino, ils sont donc connectés aux broches I2C (broches analogiques 4 et 5 sur l'Arduino Nano). Juste à côté du module transcepteur NRF24L01, un condensateur stabilise l'alimentation. Une résistance de pull-up est également connectée à la broche de données du DHT22 pour son bon fonctionnement. Côté alimentation, j'ai utilisé un adaptateur secteur 12V DC pour l'unité intérieure, et pour l'unité extérieure, deux batteries Li-ion produisant environ 7,5V. Avec cette configuration, l'unité extérieure peut fonctionner environ 10 jours avant que les batteries ne se déchargent, car nous transmettons les données périodiquement et mettons l'Arduino en mode veille entre-temps, où la consommation n'est que d'environ 7mA. Afin de garder les composants électroniques organisés, j'ai conçu un PCB personnalisé selon le schéma de câblage, en utilisant le logiciel gratuit de conception de circuits en ligne EasyEDA. On peut noter que le même PCB peut être utilisé pour l'unité intérieure et l'unité extérieure, seule la programmation de la carte Arduino diffère. Une fois la conception terminée, nous exportons simplement le fichier Gerber utilisé pour la fabrication du PCB. Vous pouvez consulter les fichiers de projet EasyEDA de la station météo sans fil Arduino ici. Ensuite, nous pouvons commander notre PCB chez JLCPCB, qui est le sponsor de cette vidéo. Ici, nous glissons-déposons simplement le fichier Gerber. Une fois téléchargé, nous pouvons examiner notre PCB dans le visualiseur Gerber. Si tout est correct, nous continuons, sélectionnons les propriétés souhaitées pour notre PCB, et passons commande à un prix raisonnable. Notez que pour votre première commande chez JLCPCB, vous pouvez obtenir jusqu'à 10 PCB pour seulement 2$. Après quelques jours, les PCB sont arrivés. La qualité est excellente et tout correspond exactement à la conception. J'ai commencé l'assemblage des composants en soudant des connecteurs à broches sur le PCB, ce qui permet de connecter et déconnecter facilement les composants au besoin. J'ai ensuite inséré et soudé le condensateur et la résistance de pull-up. Une fois cette étape terminée, nous pouvons simplement fixer les composants sur les connecteurs du PCB. Ensuite, j'ai réalisé les boîtiers du projet. J'ai utilisé du MDF de 8mm d'épaisseur et une scie circulaire pour découper toutes les pièces aux dimensions voulues. Pour obtenir des mesures précises de température et d'humidité, les côtés des boîtiers doivent laisser l'air circuler. J'ai donc percé plusieurs fentes sur les panneaux latéraux des deux unités à l'aide d'une perceuse et d'une râpe. J'ai aussi réalisé une fente pour l'écran OLED sur le panneau avant, ainsi qu'une petite pièce d'aluminium découpée à la bonne taille pour la fixer ultérieurement sur le panneau avant en guise de décoration. Pour l'assemblage des boîtiers, j'ai utilisé de la colle à bois, des serre-joints et quelques vis. J'ai peint les boîtiers avec une bombe de peinture : blanc pour l'unité extérieure, noir pour l'unité intérieure. Une fois la peinture sèche, j'ai simplement inséré les PCB dans les boîtiers. À l'arrière de l'unité intérieure, j'ai inséré une prise d'alimentation et un interrupteur, et pour l'unité extérieure, j'ai utilisé un simple cavalier comme interrupteur. Voilà, notre station météo sans fil Arduino fonctionne maintenant. Il ne reste plus qu'à examiner le fonctionnement du programme. Description : L'unité extérieure est l'émetteur de la communication sans fil. Nous incluons la bibliothèque RF24, la bibliothèque DHT, ainsi que la bibliothèque LowPower pour mettre l'Arduino en mode veille. Après avoir défini les instances, les broches et les variables, dans le setup nous initialisons l'adresse de communication sans fil. Dans la boucle loop, nous lisons d'abord les données du capteur DHT22 (température et humidité). Initialement ces valeurs sont des entiers séparés, nous les convertissons en une seule variable String, les plaçons dans un tableau de caractères, et envoyons ces données vers l'unité intérieure avec radio.write(). La boucle for envoie les données 3 fois pour s'assurer que le récepteur les reçoive même s'il est occupé au moment de l'envoi. À la fin, nous mettons l'Arduino en mode veille pour une période définie afin de minimiser la consommation d'énergie. Description : Du côté de l'unité intérieure (récepteur), nous incluons deux bibliothèques supplémentaires : une pour le module horloge temps réel DS3231 et une pour l'écran OLED, la bibliothèque U8G2. De la même manière, nous définissons les instances, les broches et les variables nécessaires. Nous définissons aussi les icônes de température et d'humidité sous forme de bitmaps. Pour créer ces bitmaps, on peut utiliser GIMP, un éditeur d'images open source, pour dessiner puis exporter en bitmap (.xbm). On ouvre ensuite ce fichier avec un bloc-notes et on copie le bitmap dans le code Arduino. Notez qu'on peut définir le bitmap comme constant avec le modificateur PROGMEM, ainsi il sera stocké en mémoire flash au lieu de la SRAM. Dans le setup, nous initialisons la communication sans fil, l'écran OLED et le module horloge temps réel. Dans la boucle loop, nous vérifions constamment s'il y a des données entrantes via les modules NRF24L01. Si c'est le cas, avec radio.read() nous les lisons et stockons les deux premiers caractères dans la variable température, et les deux suivants dans la variable humidité. Nous utilisons ensuite millis() pour afficher les différentes données sur l'écran à intervalles définis par la variable interval (3 secondes). Nous utilisons millis() au lieu de delay() pour que le reste du code puisse s'exécuter en continu, sinon nous risquerions de rater les données entrantes de l'unité extérieure. Ensuite, avec les fonctions firstPage() et nextPage() de la bibliothèque U8G2, nous affichons les cinq écrans différents définis par des fonctions personnalisées. La fonction drawDate() récupère la date et l'heure du module RTC et les affiche. La fonction drawInTemperature() lit la température intérieure et l'affiche. La même méthode s'applique pour tous les écrans. C'est tout pour ce tutoriel. J'espère que vous avez apprécié ce projet Arduino et appris quelque chose de nouveau. N'hésitez pas à poser vos questions dans les commentaires ci-dessous.Vue d'ensemble

Schéma de câblage de la station météo sans fil Arduino

PCB à conception personnalisée












Code de la station météo sans fil Arduino
Code de l'unité extérieure (émetteur) :
/* Tutoriel Communication Sans Fil Arduino - Unité extérieure - Émetteur
par Dejan Nedelkovski, www.HowToMechatronics.com
Bibliothèques: NRF24L01 - TMRh20/RF24, https://github.com/tmrh20/RF24/
DHT22 - DHTlib, https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib
LowPower - https://github.com/rocketscream/Low-Power */
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>
#include <LowPower.h>
#define dataPin 8 // Broche de données DHT22
dht DHT; // Crée un objet DHT
RF24 radio(10, 9); // CE, CSN
const byte address[6] = "00001";
char thChar[32] = "";
String thString = "";
void setup() {
radio.begin();
radio.openWritingPipe(address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
}
void loop() {
int readData = DHT.read22(dataPin); // Lecture du capteur
int t = DHT.temperature; // Température
int h = DHT.humidity; // Humidité
thString = String(t) + String(h);
thString.toCharArray(thChar, 12);
// Envoyer les données sans fil vers l'unité intérieure
for (int i = 0; i <= 3; i++) { // Envoyer 3 fois
radio.write(&thChar, sizeof(thChar));
delay(50);
}
// Mise en veille pour 2 minutes (15 x 8s = 120s)
for (int sleepCounter = 15; sleepCounter > 0; sleepCounter--) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
}Code de l'unité intérieure (récepteur) :
/* Tutoriel Communication Sans Fil Arduino - Unité intérieure - Récepteur
par Dejan Nedelkovski, www.HowToMechatronics.com
Bibliothèques: DS3231 - https://www.rinkydinkelectronics.com/library.php?id=73
U8G2 - https://github.com/olikraus/u8g2 */
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <dht.h>
#include <DS3231.h>
#include <U8g2lib.h>
#include <Wire.h>
#define dataPin 8 // Capteur DHT22
dht DHT;
DS3231 rtc(SDA, SCL);
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
RF24 radio(10, 9);
const byte address[6] = "00001";
char text[6] = "";
int readDHT22, t, h;
String inTemp, inHum, outTemp, outHum;
String rtcTime, rtcDate;
int draw_state = 0;
unsigned long previousMillis = 0;
long interval = 3000;
// Icône température (bitmap)
#define Temperature_20Icon_width 27
#define Temperature_20Icon_height 47
static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0xc0, 0xe1, 0x00, 0x00,
0xe0, 0xc0, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00,
0x60, 0x80, 0x79, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0xf9, 0x03,
0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x8c, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00,
0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00,
0x60, 0x9e, 0x79, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0xf9, 0x03,
0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x60, 0x9e, 0x01, 0x00, 0x70, 0x9e, 0x03, 0x00,
0x38, 0x1e, 0x07, 0x00, 0x18, 0x3e, 0x0e, 0x00, 0x1c, 0x3f, 0x0c, 0x00, 0x0c, 0x7f, 0x18, 0x00,
0x8c, 0xff, 0x18, 0x00, 0x8e, 0xff, 0x38, 0x00, 0xc6, 0xff, 0x31, 0x00, 0xc6, 0xff, 0x31, 0x00,
0xc6, 0xff, 0x31, 0x00, 0x8e, 0xff, 0x38, 0x00, 0x8c, 0xff, 0x18, 0x00, 0x0c, 0x7f, 0x1c, 0x00,
0x3c, 0x1c, 0x0e, 0x00, 0x78, 0x00, 0x06, 0x00, 0xe0, 0x80, 0x07, 0x00, 0xe0, 0xff, 0x03, 0x00,
0x80, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Icône humidité (bitmap)
#define Humidity_20Icon_width 27
#define Humidity_20Icon_height 47
static const unsigned char Humidity_20Icon_bits[] U8X8_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
0x00, 0xf8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8e, 0x01, 0x00,
0x00, 0x86, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x03, 0x07, 0x00, 0x80, 0x03, 0x06, 0x00,
0x80, 0x01, 0x0c, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0xc0, 0x00, 0x18, 0x00, 0xe0, 0x00, 0x38, 0x00,
0x60, 0x00, 0x30, 0x00, 0x70, 0x00, 0x70, 0x00, 0x30, 0x00, 0xe0, 0x00, 0x38, 0x00, 0xc0, 0x00,
0x18, 0x00, 0xc0, 0x01, 0x1c, 0x00, 0x80, 0x01, 0x0c, 0x00, 0x80, 0x03, 0x0e, 0x00, 0x80, 0x03,
0x06, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x06,
0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06,
0x63, 0x00, 0x00, 0x06, 0x63, 0x00, 0x00, 0x06, 0xe3, 0x00, 0x00, 0x06, 0xc7, 0x00, 0x00, 0x06,
0xc6, 0x01, 0x00, 0x07, 0x86, 0x03, 0x00, 0x03, 0x0e, 0x1f, 0x00, 0x03, 0x0e, 0x1e, 0x80, 0x01,
0x1c, 0x00, 0xc0, 0x01, 0x38, 0x00, 0xe0, 0x00, 0x78, 0x00, 0x70, 0x00, 0xf0, 0x00, 0x38, 0x00,
0xe0, 0x07, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
void setup() {
radio.begin();
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_MIN);
radio.startListening();
u8g2.begin();
rtc.begin();
}
void loop() {
if (radio.available()) {
radio.read(&text, sizeof(text));
outTemp = String(text[0]) + String(text[1]) + char(176) + "C";
outHum = String(text[2]) + String(text[3]) + "%";
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
u8g2.firstPage();
do {
switch (draw_state) {
case 0: drawDate(); break;
case 1: drawInTemperature(); break;
case 2: drawInHumidity(); break;
case 3: drawOutTemperature(); break;
case 4: drawOutHumidity(); break;
}
} while (u8g2.nextPage());
draw_state++;
if (draw_state > 4) draw_state = 0;
}
}
void drawDate() {
String dowa = rtc.getDOWStr();
dowa.remove(3);
rtcDate = dowa + " " + rtc.getDateStr();
u8g2.setFont(u8g2_font_timB14_tr);
u8g2.setCursor(0, 15);
rtcTime = rtc.getTimeStr();
rtcTime.remove(5);
u8g2.print(rtcDate);
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(8, 58);
u8g2.print(rtcTime);
}
void drawInTemperature() {
readDHT22 = DHT.read22(dataPin);
t = DHT.temperature;
inTemp = String(t) + char(176) + "C";
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(24, 15);
u8g2.print("INDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(inTemp);
u8g2.drawXBMP(0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits);
}
void drawInHumidity() {
h = DHT.humidity;
inHum = String(h) + "%";
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(24, 15);
u8g2.print("INDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(inHum);
u8g2.drawXBMP(0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits);
}
void drawOutTemperature() {
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(12, 15);
u8g2.print("OUTDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(outTemp);
u8g2.drawXBMP(0, 17, Temperature_20Icon_width, Temperature_20Icon_height, Temperature_20Icon_bits);
}
void drawOutHumidity() {
u8g2.setFont(u8g2_font_helvR14_tr);
u8g2.setCursor(12, 15);
u8g2.print("OUTDOOR");
u8g2.setFont(u8g2_font_fub30_tf);
u8g2.setCursor(36, 58);
u8g2.print(outHum);
u8g2.drawXBMP(0, 17, Humidity_20Icon_width, Humidity_20Icon_height, Humidity_20Icon_bits);
}

static const unsigned char Temperature_20Icon_bits[] U8X8_PROGMEM // Stocké en Flash
static unsigned char Temperature_20Icon_bits[] // Stocké en SRAM
Processus de fabrication
- Station météo solaire DIY avec Raspberry Pi
- Construction d'une station météo extérieure avec Raspberry Pi 2 et ADS‑WS1
- Construire une station météo Raspberry Pi qui envoie les données météo quotidiennes par email
- Station météo avancée v2.0 : Surveillance en temps réel de température, pression, humidité et altitude
- Détecteur de fréquence audio Arduino — Mesurer le pic sonore avec module haute sensibilité
- Interrupteur lumineux sans fil intelligent : Manipulateur d'interrupteur piloté par Arduino
- Morpion sur matrice LED MAX7219 avec boîtier en carton
- Construire un minuteur à rebours Arduino fiable avec afficheur 7 segments SparkFun
- Station Météo Arduino Portable à 10$ – Nano, DHT22, BMP180 et LCD