Déjà un grand merci à Sarah et Rui Santo, pour le développement de la partie HTML du programme ! C'est l'avantage du freeware, je n'ai eu qu'a adapter ce qui était existant a ce que je veux faire ... (et le langage HTML, je n'ai jamais trop fricoté avec ... mais je vais approfondir, ça a l'air rigolo ) .
Je ne vais pas détailler tout le programme ici; les commentaires dans le squetch le font tout au long de la rédaction; je ne vais que décrire les passages spécifiques .
/*********************************************************************
Thanks to Sara & Rui Santos for the JavaScript part !
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
**********************************************************************/
//Appel des sous programmes utilisés
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
// Remplacer par les paramètres d'accès au réseau
const char* ssid = "Nom du réseau";
const char* password = "Clé du réseau XXXX";
Adafruit_BME680 bme; // Choix de la communication ==> I2C
//Déclaration des variables utilisées
float temperature;
float humidity;
float pressure;
float gasResistance;
float voltBattery = 34;
float volt;
float voltCalc;
const int buttonPin = 4;
int buttonState;
int passTim;
AsyncWebServer server(80);
AsyncEventSource events("/events");
unsigned long lastTime = 0;
unsigned long timerDelay = 60000; //Règle l'interval de lecture
// Impose au BME680 de commencer les mesures
void getBME680Readings() {
unsigned long endTime = bme.beginReading();
if (endTime == 0) {
return;
}
if (!bme.endReading()) {
return;
}
temperature = bme.temperature;
pressure = (bme.pressure / 100.0) + 40; //ajustement suivant baromètre étalon de l'altitude
humidity = bme.humidity;
gasResistance = 1 / (bme.gas_resistance / 230000.0); // 1/R => plus il y a de carbone moins l'air est pur !
}
String processor(const String& var) {
getBME680Readings();
if (var == "TEMPERATURE") {
return String(temperature);
}
else if (var == "HUMIDITY") {
return String(humidity);
}
else if (var == "PRESSURE") {
return String(pressure);
}
else if (var == "GAS") {
return String(gasResistance);
}
else if (var == "VOLT") {
return String(volt);
}
else if (var == "PST") {
return String(passTim);
}
}
//Elaboration de la page HTML (Merci Sara et Rui Santo)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<title>BME680 Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="icon" href="data:,">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
p { font-size: 1.2rem;}
body { margin: 0;}
.topnav { overflow: hidden; background-color: #4B1D3F; color: white; font-size: 1.7rem; }
.content { padding: 20px; }
.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.reading { font-size: 2.8rem; }
.packet { color: #bebebe; }
.card.temperature { color: #0e7c7b; }
.card.humidity { color: #17bebb; }
.card.pressure { color: #3fca6b; }
.card.gas { color: #d62246; }
.card.battery { color: #EE8F0E; }
.card.button { color: #0EBEEE; }
</style>
</head>
<body>
<div class="topnav">
<h3>Le Temps Chez Nous</h3>
</div>
<div class="content">
<div class="cards">
<div class="card temperature">
<h4><i class="fas fa-thermometer-half"></i> TEMPERATURE</h4><p><span class="reading"><span id="temp">%TEMPERATURE%</span> °C</span></p>
</div>
<div class="card humidity">
<h4><i class="fas fa-tint"></i> HUMIDITE</h4><p><span class="reading"><span id="hum">%HUMIDITY%</span> %</span></p>
</div>
<div class="card pressure">
<h4><i class="fas fa-angle-double-down"></i> PRESSION</h4><p><span class="reading"><span id="pres">%PRESSURE%</span> hPa</span></p>
</div>
<div class="card gas">
<h4><i class="fas fa-wind"></i> POLLUTION</h4><p><span class="reading"><span id="gas">%GAS%</span> IQA</span></p>
</div>
<div class="card battery">
<h4><i class="fas fa-battery-quarter"></i> BATTERIE</h4><p><span class="reading"><span id="volt">%VOLT%</span> Volt</span></p>
</div>
<div class="card button">
<h4><i class="far fa-bell"></i> PASSAGE</h4><p><span class="reading"><span id="passTim">%PST%</span> Min</span></p>
</div>
</div>
</div>
<script>
if (!!window.EventSource) {
var source = new EventSource('/events');
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if (e.target.readyState != EventSource.OPEN) {
console.log("Events Disconnected");
}
}, false);
source.addEventListener('message', function(e) {
console.log("message", e.data);
}, false);
source.addEventListener('temperature', function(e) {
console.log("temperature", e.data);
document.getElementById("temp").innerHTML = e.data;
}, false);
source.addEventListener('humidity', function(e) {
console.log("humidity", e.data);
document.getElementById("hum").innerHTML = e.data;
}, false);
source.addEventListener('pressure', function(e) {
console.log("pressure", e.data);
document.getElementById("pres").innerHTML = e.data;
}, false);
source.addEventListener('gas', function(e) {
console.log("gas", e.data);
document.getElementById("gas").innerHTML = e.data;
}, false);
}
</script>
</body>
</html>)rawliteral" :
void setup() {
pinMode(buttonPin, INPUT);
// Reglage du circuit et du logiciel sur le point d'accès Wi-Fi
WiFi.mode(WIFI_AP_STA);
// Accorde le composant sur la sattion Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
}
// Initialisation du capteur BME680
if (!bme.begin()) {
while (1);
}
// Réglage de la rampe et initialisation du filtre
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
// Prise en charge du serveur Web
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send_P(200, "text/html", index_html, processor);
});
// Prise en charge des évenements du serveur Web
events.onConnect([](AsyncEventSourceClient * client) {
// envoi le message "hello", les milli-seconde en cours de l' id
// et remet la reconnection à 1 seconde
client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);
server.begin();
}
void loop() {
// Boucle pour une relecture après l'interval
if ((millis() - lastTime) > timerDelay) {
getBME680Readings();
// Lecture de la tension batterie
voltCalc = analogRead(voltBattery);
volt = (voltCalc * (4.9/4095));
// Lecture du temps depuis que le boutton est actif (comptage du Nb de boucle si bouton actif)
buttonState = digitalRead(buttonPin);
if (buttonState==LOW) {
passTim++;
}
else {
passTim = 0;
}
// Envoi les événements lus sur les capteurs, sur le web
events.send("ping", NULL, millis());
events.send(String(temperature).c_str(), "temperature", millis());
events.send(String(humidity).c_str(), "humidity", millis());
events.send(String(pressure).c_str(), "pressure", millis());
events.send(String(gasResistance).c_str(), "gas", millis());
events.send(String(volt).c_str(), "volt", millis());
events.send(String(passTim).c_str(), "passTim", millis());
lastTime = millis();
}
}
Et pour ceux qui sont intéressés, les fichiers de réalisation :
La version décrite plus haut; avec un module ESP32
Meteo station (192.6 Ko)
Avant la réalisation, il est un site qui est une véritable encyclopédie et qu'il faut regarder impérativement :
Ce site est une mine de connaissances; fort bien fait et très détaillés, il présente une arborescence qui permet d'aller directement sur ce que l'on cherche sans perdre de temps ! A garder précieusement dans les favoris et merci encore aux auteurs Sara & Rui Santos !
La mine d'or est ici : https://randomnerdtutorials.com/
Si vous préférez la version ESP8266 :
Pour ceux qui se sentent plus à l'aise avec les modules ESP8266, j'ai développé, sur le même principe l'équivalence !
Un gros avantage car il est moins capricieux à 'téléverser' avec l'IDE Arduino et offre la fonction "deepSleep" qui va mettre en sommeil le circuit pour une économie non négligeable de la batterie (~50 µA) .... Et on peut le réveiller avec le prince charmant (non pas du tout), par un puls low sur la borne RST venant de l'extérieur ou le timer interne par la liaison D0 sur RST. (n'établir cette liaison qu'après le téléversement du sketch sous peine de voir des gros mots s'afficher ) .... Hélas pendant le sommeil, il n'y a pas de liaison Wi-Fi ...

Et dans le ZIP ci-joint les fichiers pour la deuxième réalisation :
Meteostation esp8266 (217.87 Ko)
Pour résumer et conclure :
- Il faut une bonne surface de panneaux photovoltaique si vous voulez une autonomie suffisante .
- Pour avoir des mesures fiables, il ne faut pas laisser le boîtier en rayonnement direct avec le soleil; la mesure de tempétature se fait sous abri .
- Il sera peut-être nécessaire de retoucher le logiciel pour l'adapter à votre altitude et pression atmosphérique ! Une comparaison avec le site local de météo France permet cet étalonnage .
- J'ai décris la détection de présence de courrier dans la boîte aux lettres, mais le boîtier peut aussi bien contrôler la fermeture d'une porte, que la présence d'eau dans la cave, le niveau de remplissage des tonneaux de récupération d'eau de pluie ou le besoin d'arosage de votre cactus préféré; il suffit juste de changer l'intittulé du caption et le symbole de la case attribuée à cet effet et de mettre le capteur relatif à l'événement .
- Si vous choisissez d'alimenter le montage par un bloc secteur à découpage, il faut assurer la protection électrique et IP adéquat afin de protéger dans les règles de l'art, toutes personnes qui entreraient en contact direct ou indirect avec l'objet ou un de ses composants ...
En cas de grandes distances et si la couverture est insuffisante, je suis en train d'essayer d'augmenter la portée Wi-Fi ... Peut-être des antennes directives ou des module LoRa ! Dès les premiers résultats, je me ferai un plaisir de les publier . En tous cas bonne lecture et prenez soins de vous .