Station météo cloud DIY avec ESP32 ou ESP8266

Station météo cloud DIY avec ESP32 ou ESP8266

Construisez un tableau de bord de station météo cloud pour visualiser les lectures de vos capteurs ESP32 ou ESP8266 de n’importe où dans le monde. Vous visualiserez les données de vos capteurs affichées sur des jauges et sur un tableau. L’ESP32 ou l’ESP8266 fera une requête HTTP POST à ​​un script PHP pour insérer vos données dans une base de données MySQL.

Station météo cloud DIY avec base de données MySQL ESP32/ESP8266 et PHP

Mis à jour le 27 mars 2023

Auparavant, nous stockions les lectures des capteurs dans une base de données et les affichions sur un tableau ou des graphiques auxquels vous pouvez accéder de n’importe où en utilisant votre propre serveur. Maintenant, j’ai décidé d’aller plus loin et d’ajouter quelques informations supplémentaires à la page Web.

J’ai ajouté deux jauges pour afficher les dernières lectures de température et d’humidité ainsi que des statistiques sur les lectures minimales, maximales et moyennes à partir d’un certain nombre de lectures que vous pouvez définir. Vous pouvez également visualiser toutes les dernières lectures sur un tableau et vous pouvez sélectionner le nombre de lectures que vous souhaitez afficher.

Pour créer ce projet, vous utiliserez ces technologies :

  • ESP32 ou ESP8266 programmé avec Arduino IDE
  • Serveur d’hébergement et nom de domaine
  • Script PHP pour insérer des données dans MySQL et les afficher sur une page Web
  • Base de données MySQL pour stocker les lectures

Table des matières

Ce projet est divisé en les principales sections suivantes :

  1. Hébergement de votre application PHP et de votre base de données MySQL
  2. Préparation de votre base de données MySQL
  3. PHP Script HTTP POST – Recevoir et insérer des données dans la base de données MySQL
  4. Script PHP pour les fonctions de base de données
  5. Script PHP – Afficher les lectures de la base de données sur les jauges et le tableau
  6. Configuration de l’ESP32 ou de l’ESP8266

Regardez la démonstration vidéo

Pour voir comment fonctionne le projet, vous pouvez regarder la vidéo de démonstration suivante :

YouTube video

0. Télécharger le code source

Pour ce projet, vous aurez besoin de ces fichiers :

1. Hébergement de votre application PHP et de votre base de données MySQL

L’objectif de ce projet est d’avoir votre propre nom de domaine et compte d’hébergement qui vous permet de stocker les lectures des capteurs de l’ESP32 ou de l’ESP8266. Vous pouvez visualiser les lectures de n’importe où dans le monde en accédant à votre propre domaine de serveur.

Voici un aperçu de haut niveau du fonctionnement du projet :

Hébergement d'application PHP et de base de données MySQL ESP32 ESP8266 Vue d'ensemble du projet de station météo Gauge
  1. Vous avez un ESP32 ou ESP8266 qui envoie les lectures des capteurs à votre propre serveur. Pour cela, vous avez votre carte connectée à votre routeur ;
  2. Dans votre serveur, il y a un script PHP qui vous permet de stocker vos lectures dans une base de données MySQL ;
  3. Ensuite, un autre script PHP affichera la page Web avec les jauges, le tableau et toutes les autres informations ;
  4. Enfin, vous pouvez visualiser les lectures de n’importe où dans le monde en accédant à votre propre nom de domaine.

Services d’hébergement

Je recommande d’utiliser l’un des services d’hébergement suivants qui peuvent gérer toutes les exigences du projet :

  • Bluehost (convivial avec cPanel) : nom de domaine gratuit lors de la souscription au plan de 3 ans. Je recommande de choisir l’option de sites Web illimités ;
  • Digital Ocean : serveur Linux que vous gérez via une ligne de commande. Je n’ai recommandé cette option qu’aux utilisateurs avancés.

Ces deux services sont ceux que j’utilise et que je recommande personnellement, mais vous pouvez utiliser n’importe quel autre service d’hébergement. Tout service d’hébergement proposant PHP et MySQL fonctionnera avec ce didacticiel. Si vous n’avez pas de compte d’hébergement, je vous recommande de vous inscrire à Bluehost.

Obtenez un hébergement et un nom de domaine avec Bluehost »

Lors de l’achat d’un compte d’hébergement, vous devrez également acheter un nom de domaine. C’est ce qui rend ce projet intéressant : vous pourrez accéder à votre nom de domaine (https://example.com) et voir vos relevés ESP.

Si vous aimez nos projets, vous pourriez envisager de vous inscrire à l’un des services d’hébergement recommandés, car vous soutiendrez notre travail.

Remarque : vous pouvez également exécuter un serveur LAMP (Linux, Apache, MySQL, PHP) sur un Raspberry Pi pour accéder aux données de votre réseau local. Cependant, le but de ce tutoriel est de publier des lectures dans votre propre nom de domaine auquel vous pouvez accéder de n’importe où dans le monde. Cela vous permet d’accéder facilement à vos lectures ESP sans dépendre d’une plate-forme IoT tierce.

2. Préparation de votre base de données MySQL

Après avoir créé un compte d’hébergement et configuré un nom de domaine, vous pouvez vous connecter à votre cPanel ou à un tableau de bord similaire. Après cela, suivez les étapes suivantes pour créer votre base de données, votre nom d’utilisateur, votre mot de passe et votre table SQL.

Création d’une base de données et d’un utilisateur

Ouvrez l’onglet « Avancé »:

Onglet Avancé de Bluehost

1. Tapez « base de données » dans la barre de recherche et sélectionnez « Assistant de base de données MySQL ».

CPanel sélectionne l'assistant de base de données MySQL pour créer une base de données

2. Entrez le nom de votre base de données souhaitée. Dans mon cas, le nom de la base de données est esp_data. Ensuite, appuyez sur le bouton « Étape suivante » :

ESP32 ESP8266 CPanel Créer une base de données MySQL

Remarque : plus tard, vous devrez utiliser le nom de la base de données avec le préfixe que votre hébergeur vous donne (mon préfixe de base de données dans la capture d’écran ci-dessus est flou). Je l’appellerai désormais example_esp_data.

3. Tapez votre nom d’utilisateur de base de données et définissez un mot de passe. Vous devez enregistrer tous ces détails car vous en aurez besoin plus tard pour établir une connexion à la base de données avec votre code PHP.

ESP32 ESP8266 CPanel Créer un utilisateur et un mot de passe de base de données MySQL

C’est ça! Votre nouvelle base de données et votre nouvel utilisateur ont été créés avec succès. Maintenant, enregistrez toutes vos informations, car vous en aurez besoin plus tard :

  • Nom de la base de données : example_esp_data
  • Nom d’utilisateur : example_esp_board
  • Mot de passe : votre mot de passe

Création d’un tableau SQL

Après avoir créé votre base de données et votre utilisateur, revenez au tableau de bord cPanel et recherchez « phpMyAdmin ».

ESP32 ESP8266 CPanel Ouvrir PHPMyAdmin

Dans la barre latérale gauche, sélectionnez le nom de votre base de données example_esp_data et ouvrez l’onglet « SQL ».

ESP32 ESP8266 Base de données ouverte PHPMyAdmin

Important : assurez-vous d’avoir ouvert la base de données example_esp_data. Ensuite, cliquez sur l’onglet SQL. Si vous ne suivez pas ces étapes exactes et n’exécutez pas la requête SQL, vous risquez de créer une table dans la mauvaise base de données.

Copiez la requête SQL dans l’extrait de code suivant :

CREATE TABLE SensorData (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    sensor VARCHAR(30) NOT NULL,
    location VARCHAR(30) NOT NULL,
    value1 VARCHAR(10),
    value2 VARCHAR(10),
    value3 VARCHAR(10),
    reading_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)

Afficher le code brut

Collez-le dans le champ de requête SQL (surligné d’un rectangle rouge) et appuyez sur le bouton « Go » pour créer votre table :

ESP32 ESP8266 PHPMyAdmin Créer une table SQL

Après cela, vous devriez voir votre table nouvellement créée appelée SensorData dans la base de données example_esp_data, comme illustré dans la figure ci-dessous :

ESP32 ESP8266 PHPMyAdmin Afficher la base de données SQL

3. PHP Script HTTP POST – Recevoir et insérer des données dans la base de données MySQL

Dans cette section, nous allons créer un script PHP chargé de recevoir les requêtes entrantes de l’ESP32 ou de l’ESP8266 et d’insérer les données dans une base de données MySQL.

Si vous utilisez un fournisseur d’hébergement avec cPanel, vous pouvez rechercher « Gestionnaire de fichiers » :

ESP32 ESP8266 CPanel Open Edit PHP Files with File Manager

Ensuite, sélectionnez l’option public_html et appuyez sur le bouton « + Fichier » pour créer un nouveau fichier .php.

ESP32 ESP8266 CPanel Créer un nouveau fichier PHP

Remarque : si vous suivez ce tutoriel et que vous n’êtes pas familier avec PHP ou MySQL, je vous recommande de créer ces fichiers exacts. Sinon, vous devrez modifier l’esquisse ESP fournie avec différents chemins d’URL.

Créez un nouveau fichier dans /public_html avec ce nom et cette extension exacts : esp-post-data.php

Créer un fichier PHP de données de publication esp

Modifiez le fichier nouvellement créé (esp-post-data.php) et copiez l’extrait suivant :

<!--
  Rui Santos
  Complete project details at https://Raspberryme.com/cloud-weather-station-esp32-esp8266/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
-->
<?php
  include_once('esp-database.php');

  // Keep this API Key value to be compatible with the ESP code provided in the project page. If you change this value, the ESP sketch needs to match
  $api_key_value = "tPmAT5Ab3j7F9";

  $api_key= $sensor = $location = $value1 = $value2 = $value3 = "";

  if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $api_key = test_input($_POST["api_key"]);
    if($api_key == $api_key_value) {
      $sensor = test_input($_POST["sensor"]);
      $location = test_input($_POST["location"]);
      $value1 = test_input($_POST["value1"]);
      $value2 = test_input($_POST["value2"]);
      $value3 = test_input($_POST["value3"]);

      $result = insertReading($sensor, $location, $value1, $value2, $value3);
      echo $result;
    }
    else {
      echo "Wrong API Key provided.";
    }
  }
  else {
    echo "No data posted with HTTP POST.";
  }

  function test_input($data) {
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;
  }

Afficher le code brut

4. Script PHP pour les fonctions de base de données

Créez un nouveau fichier dans /public_html responsable de l’insertion et de l’accès aux données de votre base de données. Nommez votre fichier : esp-database.php

Créer un fichier PHP de base de données esp

Copiez ce script PHP :

<!--
  Rui Santos
  Complete project details at https://Raspberryme.com/cloud-weather-station-esp32-esp8266/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
-->
<?php
  $servername = "localhost";

  // REPLACE with your Database name
  $dbname = "REPLACE_WITH_YOUR_DATABASE_NAME";
  // REPLACE with Database user
  $username = "REPLACE_WITH_YOUR_USERNAME";
  // REPLACE with Database user password
  $password = "REPLACE_WITH_YOUR_PASSWORD";

  function insertReading($sensor, $location, $value1, $value2, $value3) {
    global $servername, $username, $password, $dbname;

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    $sql = "INSERT INTO SensorData (sensor, location, value1, value2, value3)
    VALUES ('" . $sensor . "', '" . $location . "', '" . $value1 . "', '" . $value2 . "', '" . $value3 . "')";

    if ($conn->query($sql) === TRUE) {
      return "New record created successfully";
    }
    else {
      return "Error: " . $sql . "<br>" . $conn->error;
    }
    $conn->close();
  }
  
  function getAllReadings($limit) {
    global $servername, $username, $password, $dbname;

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    $sql = "SELECT id, sensor, location, value1, value2, value3, reading_time FROM SensorData order by reading_time desc limit " . $limit;
    if ($result = $conn->query($sql)) {
      return $result;
    }
    else {
      return false;
    }
    $conn->close();
  }
  function getLastReadings() {
    global $servername, $username, $password, $dbname;

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    $sql = "SELECT id, sensor, location, value1, value2, value3, reading_time FROM SensorData order by reading_time desc limit 1" ;
    if ($result = $conn->query($sql)) {
      return $result->fetch_assoc();
    }
    else {
      return false;
    }
    $conn->close();
  }

  function minReading($limit, $value) {
     global $servername, $username, $password, $dbname;

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    $sql = "SELECT MIN(" . $value . ") AS min_amount FROM (SELECT " . $value . " FROM SensorData order by reading_time desc limit " . $limit . ") AS min";
    if ($result = $conn->query($sql)) {
      return $result->fetch_assoc();
    }
    else {
      return false;
    }
    $conn->close();
  }

  function maxReading($limit, $value) {
     global $servername, $username, $password, $dbname;

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    $sql = "SELECT MAX(" . $value . ") AS max_amount FROM (SELECT " . $value . " FROM SensorData order by reading_time desc limit " . $limit . ") AS max";
    if ($result = $conn->query($sql)) {
      return $result->fetch_assoc();
    }
    else {
      return false;
    }
    $conn->close();
  }

  function avgReading($limit, $value) {
     global $servername, $username, $password, $dbname;

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }

    $sql = "SELECT AVG(" . $value . ") AS avg_amount FROM (SELECT " . $value . " FROM SensorData order by reading_time desc limit " . $limit . ") AS avg";
    if ($result = $conn->query($sql)) {
      return $result->fetch_assoc();
    }
    else {
      return false;
    }
    $conn->close();
  }
?>

Afficher le code brut

Avant d’enregistrer le fichier, vous devez modifier les variables $dbname, $username et $password avec vos détails uniques :

// Your Database name
$dbname = "example_esp_data";
// Your Database user
$username = "example_esp_board";
// Your Database user password
$password = "YOUR_USER_PASSWORD";

Après avoir ajouté le nom de la base de données, le nom d’utilisateur et le mot de passe, enregistrez le fichier et continuez avec ce didacticiel. Si vous essayez d’accéder à votre nom de domaine dans le chemin d’URL suivant, vous verrez ce qui suit :

https://example.com/esp-post-data.php
esp poster des données via un exemple de fichier PHP HTTP

5. PHP Script – Afficher les lectures de la base de données sur les jauges et le tableau

Vous devrez également ajouter un fichier CSS pour styliser votre tableau de bord, nommez-le : esp-style.css :

Créer un fichier CSS de style esp

Copiez ce CSS dans votre fichier et enregistrez-le :

/**
  Rui Santos
  Complete project details at https://Raspberryme.com/cloud-weather-station-esp32-esp8266/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
**/
body {
    width: 60%;
    margin: auto;
    text-align: center;
    font-family: Arial;
    top: 50%;
    left: 50%;
}

@media screen and (max-width: 800px) {
    body {
        width: 100%;
    }
}

table {
    margin-left: auto;
    margin-right: auto;
}

div {
    margin-left: auto;
    margin-right: auto;
}

h2 { font-size: 2.5rem; }

.header {
	 padding: 1rem;
	 margin: 0 0 2rem 0;
	 background: #f2f2f2;
}

h1 {
    font-size: 2rem;
    font-family: Arial, sans-serif;
    text-align: center;
    text-transform: uppercase;
}

.content {
    display: flex;
}

@media screen and (max-width: 500px) /* Mobile */ {
    .content {
        flex-direction: column;
    }
}

.mask {
    position: relative;
    overflow: hidden;
    display: block;
    width: 12.5rem;
    height: 6.25rem;
    margin: 1.25rem;
}

.semi-circle {
    position: relative;
    display: block;
    width: 12.5rem;
    height: 6.25rem;
    background: linear-gradient(to right, #3498db 0%, #05b027 33%, #f1c40f 70%, #c0392b 100%);
    border-radius: 50% 50% 50% 50% / 100% 100% 0% 0%;
}

.semi-circle::before {
    content: "";
    position: absolute;
    bottom: 0;
    left: 50%;
    z-index: 2;
    display: block;
    width: 8.75rem;
    height: 4.375rem;
    margin-left: -4.375rem;
    background: #fff;
    border-radius: 50% 50% 50% 50% / 100% 100% 0% 0%;
}

.semi-circle--mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 12.5rem;
    height: 12.5rem;
    background: transparent;
    transform: rotate(120deg) translate3d(0, 0, 0);
    transform-origin: center center;
    backface-visibility: hidden;
    transition: all 0.3s ease-in-out;
}

.semi-circle--mask::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0%;
    z-index: 2;
    display: block;
    width: 12.625rem;
    height: 6.375rem;
    margin: -1px 0 0 -1px;
    background: #f2f2f2;
    border-radius: 50% 50% 50% 50% / 100% 100% 0% 0%;
}

.gauge--2 .semi-circle { background: #3498db; }

.gauge--2 .semi-circle--mask { transform: rotate(20deg) translate3d(0, 0, 0); }

#tableReadings { border-collapse: collapse; }

#tableReadings td, #tableReadings th {
    border: 1px solid #ddd;
    padding: 10px;
}

#tableReadings tr:nth-child(even){ background-color: #f2f2f2; }

#tableReadings tr:hover { background-color: #ddd; }

#tableReadings th {
    padding: 10px;
    background-color: #2f4468;
    color: white;
}

Afficher le code brut

Enfin, créez un autre fichier PHP dans le répertoire /public_html qui affichera tout le contenu de la base de données sur une page Web. Nommez votre nouveau fichier : esp-weather-station.php

Créer un fichier PHP de station météo esp

Editez le fichier nouvellement créé (esp-weather-station.php) et copiez le code suivant :

<!--
  Rui Santos
  Complete project details at https://Raspberryme.com/cloud-weather-station-esp32-esp8266/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
-->
<?php
    include_once('esp-database.php');
    if (isset($_GET["readingsCount"])){
      $data = $_GET["readingsCount"];
      $data = trim($data);
      $data = stripslashes($data);
      $data = htmlspecialchars($data);
      $readings_count = $_GET["readingsCount"];
    }
    // default readings count set to 20
    else {
      $readings_count = 20;
    }

    $last_reading = getLastReadings();
    $last_reading_temp = $last_reading["value1"];
    $last_reading_humi = $last_reading["value2"];
    $last_reading_time = $last_reading["reading_time"];

    // Uncomment to set timezone to - 1 hour (you can change 1 to any number)
    //$last_reading_time = date("Y-m-d H:i:s", strtotime("$last_reading_time - 1 hours"));
    // Uncomment to set timezone to + 7 hours (you can change 7 to any number)
    //$last_reading_time = date("Y-m-d H:i:s", strtotime("$last_reading_time + 7 hours"));

    $min_temp = minReading($readings_count, 'value1');
    $max_temp = maxReading($readings_count, 'value1');
    $avg_temp = avgReading($readings_count, 'value1');

    $min_humi = minReading($readings_count, 'value2');
    $max_humi = maxReading($readings_count, 'value2');
    $avg_humi = avgReading($readings_count, 'value2');
?>

<!DOCTYPE html>
<html>
    <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">

        <link rel="stylesheet" type="text/css" href="https://www.raspberryme.com/cloud-weather-station-esp32-esp8266/esp-style.css">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    </head>
    <header class="header">
        <h1>???? ESP Weather Station</h1>
        <form method="get">
            <input type="number" name="readingsCount" min="1" placeholder="Number of readings (<?php echo $readings_count; ?>)">
            <input type="submit" value="UPDATE">
        </form>
    </header>
<body>
    <p>Last reading: <?php echo $last_reading_time; ?></p>
    <section class="content">
	    <div class="box gauge--1">
	    <h3>TEMPERATURE</h3>
              <div class="mask">
			  <div class="semi-circle"></div>
			  <div class="semi-circle--mask"></div>
			</div>
		    <p style="font-size: 30px;" id="temp">--</p>
		    <table cellspacing="5" cellpadding="5">
		        <tr>
		            <th colspan="3">Temperature <?php echo $readings_count; ?> readings</th>
	            </tr>
		        <tr>
		            <td>Min</td>
                    <td>Max</td>
                    <td>Average</td>
                </tr>
                <tr>
                    <td><?php echo $min_temp['min_amount']; ?> &deg;C</td>
                    <td><?php echo $max_temp['max_amount']; ?> &deg;C</td>
                    <td><?php echo round($avg_temp['avg_amount'], 2); ?> &deg;C</td>
                </tr>
            </table>
        </div>
        <div class="box gauge--2">
            <h3>HUMIDITY</h3>
            <div class="mask">
                <div class="semi-circle"></div>
                <div class="semi-circle--mask"></div>
            </div>
            <p style="font-size: 30px;" id="humi">--</p>
            <table cellspacing="5" cellpadding="5">
                <tr>
                    <th colspan="3">Humidity <?php echo $readings_count; ?> readings</th>
                </tr>
                <tr>
                    <td>Min</td>
                    <td>Max</td>
                    <td>Average</td>
                </tr>
                <tr>
                    <td><?php echo $min_humi['min_amount']; ?> %</td>
                    <td><?php echo $max_humi['max_amount']; ?> %</td>
                    <td><?php echo round($avg_humi['avg_amount'], 2); ?> %</td>
                </tr>
            </table>
        </div>
    </section>
<?php
    echo   '<h2> View Latest ' . $readings_count . ' Readings</h2>
            <table cellspacing="5" cellpadding="5" id="tableReadings">
                <tr>
                    <th>ID</th>
                    <th>Sensor</th>
                    <th>Location</th>
                    <th>Value 1</th>
                    <th>Value 2</th>
                    <th>Value 3</th>
                    <th>Timestamp</th>
                </tr>';

    $result = getAllReadings($readings_count);
        if ($result) {
        while ($row = $result->fetch_assoc()) {
            $row_id = $row["id"];
            $row_sensor = $row["sensor"];
            $row_location = $row["location"];
            $row_value1 = $row["value1"];
            $row_value2 = $row["value2"];
            $row_value3 = $row["value3"];
            $row_reading_time = $row["reading_time"];
            // Uncomment to set timezone to - 1 hour (you can change 1 to any number)
            //$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time - 1 hours"));
            // Uncomment to set timezone to + 7 hours (you can change 7 to any number)
            //$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time + 7 hours"));

            echo '<tr>
                    <td>' . $row_id . '</td>
                    <td>' . $row_sensor . '</td>
                    <td>' . $row_location . '</td>
                    <td>' . $row_value1 . '</td>
                    <td>' . $row_value2 . '</td>
                    <td>' . $row_value3 . '</td>
                    <td>' . $row_reading_time . '</td>
                  </tr>';
        }
        echo '</table>';
        $result->free();
    }
?>

<script>
    var value1 = <?php echo $last_reading_temp; ?>;
    var value2 = <?php echo $last_reading_humi; ?>;
    setTemperature(value1);
    setHumidity(value2);

    function setTemperature(curVal){
    	//set range for Temperature in Celsius -5 Celsius to 38 Celsius
    	var minTemp = -5.0;
    	var maxTemp = 38.0;
        //set range for Temperature in Fahrenheit 23 Fahrenheit to 100 Fahrenheit
    	//var minTemp = 23;
    	//var maxTemp = 100;

    	var newVal = scaleValue(curVal, [minTemp, maxTemp], [0, 180]);
    	$('.gauge--1 .semi-circle--mask').attr({
    		style: '-webkit-transform: rotate(' + newVal + 'deg);' +
    		'-moz-transform: rotate(' + newVal + 'deg);' +
    		'transform: rotate(' + newVal + 'deg);'
    	});
    	$("#temp").text(curVal + ' ºC');
    }

    function setHumidity(curVal){
    	//set range for Humidity percentage 0 % to 100 %
    	var minHumi = 0;
    	var maxHumi = 100;

    	var newVal = scaleValue(curVal, [minHumi, maxHumi], [0, 180]);
    	$('.gauge--2 .semi-circle--mask').attr({
    		style: '-webkit-transform: rotate(' + newVal + 'deg);' +
    		'-moz-transform: rotate(' + newVal + 'deg);' +
    		'transform: rotate(' + newVal + 'deg);'
    	});
    	$("#humi").text(curVal + ' %');
    }

    function scaleValue(value, from, to) {
        var scale = (to[1] - to[0]) / (from[1] - from[0]);
        var capped = Math.min(from[1], Math.max(from[0], value)) - from[0];
        return ~~(capped * scale + to[0]);
    }
</script>
</body>
</html>

Afficher le code brut

Si vous essayez d’accéder à votre nom de domaine dans le chemin d’URL suivant, vous verrez ce qui suit :

https://example.com/esp-weather-station.php
Tableau de bord de test vide de la station météo ESP32 ESP8266

C’est ça! Si vous voyez cette page Web avec des valeurs vides dans votre navigateur, cela signifie que tout est prêt. Dans la section suivante, vous apprendrez à insérer des données de votre ESP32 ou ESP8266 dans la base de données.

6. Configuration de l’ESP32 ou de l’ESP8266

Ce projet est compatible avec les cartes ESP32 et ESP8266. Il vous suffit d’assembler un circuit simple et de télécharger le croquis fourni pour insérer la température, l’humidité, la pression, etc. dans votre base de données toutes les 10 minutes. Le croquis est légèrement différent pour chaque planche.

Cartes de développement ESP32 vs ESP8266

Pièces requises

Pour cet exemple, nous obtiendrons les lectures du capteur du capteur BME280. Voici une liste des pièces dont vous avez besoin pour construire le circuit pour ce projet :

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1680719955 120 Station meteo cloud DIY avec ESP32 ou ESP8266

Schémas

Le module de capteur BME280 que nous utilisons communique via le protocole de communication I2C, vous devez donc le connecter aux broches ESP32 ou ESP8266 I2C.

Câblage BME280 vers ESP32

Les broches ESP32 I2C sont :

  • GPIO 22 : SCL (SCK)
  • GPIO 21 : SDA (SDI)

Alors, assemblez votre circuit comme indiqué dans le diagramme schématique suivant (Guide pour ESP32 avec serveur Web BME280 et ESP32 BME280).

Câblage BME280 vers ESP32

Lecture recommandée : Guide de référence du brochage ESP32

Câblage BME280 vers ESP8266

Les broches ESP8266 I2C sont :

  • GPIO 5 (D1): SCL (SCK)
  • GPIO 4 (D2) : SDA (SDI)

Assemblez votre circuit comme dans le schéma suivant si vous utilisez une carte ESP8266 (lisez le Guide pour ESP8266 avec BME280).

Câblage BME280 vers ESP8266

Lecture recommandée : Guide de référence du brochage ESP8266

Installation des bibliothèques

Nous allons programmer l’ESP32/ESP8266 à l’aide de l’IDE Arduino, vous devez donc avoir le module complémentaire ESP installé dans votre IDE Arduino.

Suivez l’un des tutoriels suivants en fonction de la carte que vous utilisez :

Code ESP32

Suivez cette section si vous utilisez un ESP32. Pour un ESP8266 cliquez ici.

Après avoir installé les modules complémentaires de carte nécessaires, copiez le code suivant dans votre IDE Arduino, mais ne le téléchargez pas encore. Vous devez apporter quelques modifications pour que cela fonctionne pour vous.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-esp8266-mysql-database-php/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

*/

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// REPLACE with your Domain name and URL path or IP address with path
const char* serverName = "https://example.com/esp-post-data.php";

// Keep this API Key value to be compatible with the PHP code provided in the project page. 
// If you change the apiKeyValue value, the PHP file /post-esp-data.php also needs to have the same key 
String apiKeyValue = "tPmAT5Ab3j7F9";

String sensorName = "BME280";
String sensorLocation = "Office";

/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme;  // I2C
//Adafruit_BME280 bme(BME_CS);  // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);  // software SPI

void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) { 
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  // (you can also pass in a Wire library object like &Wire2)
  bool status = bme.begin(0x76);
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring or change I2C address!");
    while (1);
  }
}

void loop() {
  //Check WiFi connection status
  if(WiFi.status()== WL_CONNECTED){
    WiFiClientSecure *client = new WiFiClientSecure;
    client->setInsecure(); //don't use SSL certificate
    HTTPClient https;
    
    // Your Domain name with URL path or IP address with path
    https.begin(*client, serverName);
    
    // Specify content-type header
    https.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    // Prepare your HTTP POST request data
    String httpRequestData = "api_key=" + apiKeyValue + "&sensor=" + sensorName
                          + "&location=" + sensorLocation + "&value1=" + String(bme.readTemperature())
                          + "&value2=" + String(bme.readHumidity()) + "&value3=" + String(bme.readPressure()/100.0F) + "";
    Serial.print("httpRequestData: ");
    Serial.println(httpRequestData);
    
    // You can comment the httpRequestData variable above
    // then, use the httpRequestData variable below (for testing purposes without the BME280 sensor)
    //String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BME280&location=Office&value1=24.75&value2=49.54&value3=1005.14";

    // Send HTTP POST request
    int httpResponseCode = https.POST(httpRequestData);
     
    // If you need an HTTP request with a content type: text/plain
    //https.addHeader("Content-Type", "text/plain");
    //int httpResponseCode = https.POST("Hello, World!");
    
    // If you need an HTTP request with a content type: application/json, use the following:
    //https.addHeader("Content-Type", "application/json");
    //int httpResponseCode = https.POST("{\"value1\":\"19\",\"value2\":\"67\",\"value3\":\"78\"}");
    
    if (httpResponseCode>0) {
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);
    }
    else {
      Serial.print("Error code: ");
      Serial.println(httpResponseCode);
    }
    // Free resources
    https.end();
  }
  else {
    Serial.println("WiFi Disconnected");
  }
  //Send an HTTP POST request every 30 seconds
  delay(30000);  
}

Afficher le code brut

Définition de vos identifiants réseau

Vous devez modifier les lignes suivantes avec vos identifiants réseau : SSID et mot de passe. Le code est bien commenté sur l’endroit où vous devez apporter les modifications.

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Définition de votre nom de serveur

Vous devez également saisir votre nom de domaine, afin que l’ESP publie les lectures sur votre propre serveur.

const char* serverName = "https://example.com/esp-post-data.php";

Maintenant, vous pouvez télécharger le code sur votre tableau.

Remarque : La plupart des serveurs nécessitent que vous fassiez des requêtes HTTPS. Le code ci-dessus rend les requêtes HTTPS conformes aux exigences de la plupart des serveurs cloud de nos jours.

Votre serveur ne supporte pas le HTTPS ? Utilisez plutôt ce code.

Comment fonctionne le code

Ce projet est déjà assez long, nous ne détaillerons donc pas le fonctionnement du code, mais voici un petit résumé :

  • Importez toutes les bibliothèques pour le faire fonctionner ;
  • Définissez les variables que vous voudrez peut-être modifier (apiKeyValue, sensorName, sensorLocation) ;
  • L’apiKeyValue est juste une chaîne aléatoire que vous pouvez modifier. Il est utilisé pour des raisons de sécurité, de sorte que seule toute personne connaissant votre clé API peut publier des données dans votre base de données ;
  • Initialisez la communication série à des fins de débogage ;
  • Établissez une connexion Wi-Fi avec votre routeur ;
  • Initialisez le BME280 pour obtenir des lectures ;
  • Initialisez un client WiFi sécurisé.

Ensuite, dans la boucle () est l’endroit où vous effectuez réellement la requête HTTP POST toutes les 10 minutes avec les dernières lectures BME280 :

// Your Domain name with URL path or IP address with path
http.begin(serverName);

// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");

// Prepare your HTTP POST request data
String httpRequestData = "api_key=" + apiKeyValue + "&sensor=" + sensorName                      + "&location=" + sensorLocation + "&value1=" + String(bme.readTemperature())                      + "&value2=" + String(bme.readHumidity()) + "&value3=" + String(bme.readPressure()/100.0F) + "";

int httpResponseCode = http.POST(httpRequestData);

Vous pouvez commenter la variable httpRequestData ci-dessus qui concatène toutes les lectures BME280 et utiliser la variable httpRequestData ci-dessous à des fins de test :

String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BME280&location=Office&value1=24.75&value2=49.54&value3=1005.14";

En savoir plus sur les requêtes HTTPS avec l’ESP32 : requêtes HTTPS ESP32 (Arduino IDE).

Code ESP8266

Suivez cette section si vous utilisez un ESP8266. Pour un ESP32, consultez la section ci-dessus.

Après avoir installé les modules complémentaires et les bibliothèques de cartes nécessaires, copiez le code suivant dans votre IDE Arduino, mais ne le téléchargez pas encore. Vous devez apporter quelques modifications pour que cela fonctionne pour vous.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-esp8266-mysql-database-php/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

*/

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// REPLACE with your Domain name and URL path or IP address with path
const char* serverName = "https://example.com/esp-post-data.php";

// Keep this API Key value to be compatible with the PHP code provided in the project page. 
// If you change the apiKeyValue value, the PHP file /post-esp-data.php also needs to have the same key 
String apiKeyValue = "tPmAT5Ab3j7F9";

String sensorName = "BME280";
String sensorLocation = "Office";

/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme;  // I2C
//Adafruit_BME280 bme(BME_CS);  // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);  // software SPI

void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) { 
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());

  // (you can also pass in a Wire library object like &Wire2)
  bool status = bme.begin(0x76);
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring or change I2C address!");
    while (1);
  }
}

void loop() {
  //Check WiFi connection status
  if(WiFi.status()== WL_CONNECTED){

    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);

    // Ignore SSL certificate validation
    client->setInsecure();
    
    //create an HTTPClient instance
    HTTPClient https;
    
    // Your Domain name with URL path or IP address with path
    https.begin(*client, serverName);
    
    // Specify content-type header
    https.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    // Prepare your HTTP POST request data
    String httpRequestData = "api_key=" + apiKeyValue + "&sensor=" + sensorName
                          + "&location=" + sensorLocation + "&value1=" + String(bme.readTemperature())
                          + "&value2=" + String(bme.readHumidity()) + "&value3=" + String(bme.readPressure()/100.0F) + "";
    Serial.print("httpRequestData: ");
    Serial.println(httpRequestData);
    
    // You can comment the httpRequestData variable above
    // then, use the httpRequestData variable below (for testing purposes without the BME280 sensor)
    //String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BME280&location=Office&value1=24.75&value2=49.54&value3=1005.14";

    // Send HTTP POST request
    int httpResponseCode = https.POST(httpRequestData);
     
    // If you need an HTTP request with a content type: text/plain
    //http.addHeader("Content-Type", "text/plain");
    //int httpResponseCode = https.POST("Hello, World!");
    
    // If you need an HTTP request with a content type: application/json, use the following:
    //http.addHeader("Content-Type", "application/json");
    //int httpResponseCode = https.POST("{\"value1\":\"19\",\"value2\":\"67\",\"value3\":\"78\"}");
        
    if (httpResponseCode>0) {
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);
    }
    else {
      Serial.print("Error code: ");
      Serial.println(httpResponseCode);
    }
    // Free resources
    https.end();
  }
  else {
    Serial.println("WiFi Disconnected");
  }
  //Send an HTTP POST request every 30 seconds
  delay(30000);  
}

Afficher le code brut

Définition de vos identifiants réseau

Vous devez modifier les lignes suivantes avec vos identifiants réseau : SSID et mot de passe. Le code est bien commenté sur l’endroit où vous devez apporter les modifications.

// Replace with your network credentials
const char* ssid     = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Définition de votre nom de serveur

Vous devez également saisir votre nom de domaine, afin que l’ESP publie les lectures sur votre propre serveur.

const char* serverName = "https://example.com/esp-post-data.php";

Maintenant, vous pouvez télécharger le code sur votre tableau.

Remarque : La plupart des serveurs nécessitent que vous fassiez des requêtes HTTPS. Le code ci-dessus rend les requêtes HTTPS conformes aux exigences de la plupart des serveurs cloud de nos jours.

Votre serveur ne supporte pas le HTTPS ? Utilisez plutôt ce code.

En savoir plus sur les requêtes HTTPS avec l’ESP8266 : ESP8266 NodeMCU HTTPS Requests (Arduino IDE).

Manifestation

Après avoir terminé toutes les étapes, laissez votre carte ESP collecter des lectures et les publier sur votre serveur.

ESP32 BME280 Arduino IDE MySQL

Si tout est correct, voici ce que vous devriez voir dans votre moniteur série Arduino IDE :

Moniteur série Arduino IDE ESP32 ESP8266 Station météo

Si vous ouvrez votre nom de domaine dans ce chemin URL :

https://example.com/esp-weather-station.php

Vous devriez voir les 20 dernières lectures stockées dans votre base de données. Il y a deux jauges qui affichent les dernières lectures de température et d’humidité, et un horodatage.

Actualisez la page Web pour voir les dernières lectures :

Exemple de données de station météo ESP32 ESP8266 Jauges de température et d'humidité

Il y a un champ où tu peux taper le nombre de lectures à visualiser, ainsi que le nombre de lectures pour ces statistiques : minimum, maximum et moyenne. Par défaut, il est défini sur 20. Par exemple, si vous tapez 30 et appuyez sur le bouton de mise à jour, vous verrez que votre page Web se met à jour et recalcule toutes les valeurs.

champ de saisie esp32 esp8266 station météo

La page Web est également adaptée aux mobiles, vous pouvez donc utiliser n’importe quel appareil pour y accéder :

ESP32 ESP8266 Station météo Données mobile page Web réactive smartphone

Vous pouvez également vous rendre sur phpMyAdmin pour gérer les données stockées dans votre table SensorData. Vous pouvez le supprimer, le modifier, etc…

ESP32 ESP8266 Afficher les relevés des capteurs Base de données SQL PHPMyAdmin

Conclusion

Dans ce didacticiel, vous avez appris à publier des données de capteur dans une base de données de votre propre domaine de serveur à laquelle vous pouvez accéder depuis n’importe où dans le monde. Cela nécessite que vous ayez votre propre serveur et nom de domaine (alternativement, vous pouvez utiliser un serveur Raspberry Pi LAMP pour un accès local).

Je vous encourage à modifier l’apparence de la page Web, à ajouter plus de fonctionnalités (comme les notifications par e-mail), à publier les données de différents capteurs, à utiliser plusieurs cartes ESP, et bien plus encore.

Vous aimerez peut-être aussi lire :

Apprenez-en plus sur l’ESP32 et l’ESP8266 avec nos ressources :

Merci pour la lecture.

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video