Le blog personnel d'un lycéen

[Loisir] Système intelligent de pulvérisation d'eau et de refroidissement ESP32

Points forts du projet

  • [x] Contrôle via page web: Accédez à l'IP de l'appareil pour consulter en temps réel la température et l'état de l'automatisation
  • [x] Double mode manuel/automatique: Activez ou désactivez l'arrosage à tout moment via la page web (le mode manuel désactive temporairement l'automatisation pour éviter le gaspillage d'eau)
  • [x] Contrôle intelligent de la température: En mode automatique, l'eau s'ouvre automatiquement lorsque la température ≥30℃, et s'arrête automatiquement lorsque <30℃
  • [ ] La page web n'a pas encore de CSS, elle sert uniquement de démonstration fonctionnelle, vous pouvez l'embellir selon vos besoins

Origine : La climatisation est tombée en panne, le problème venait de l'unité extérieure

L'été 2024 dans le Hubei a été particulièrement difficile, la climatisation de la maison refroidissait très mal, pratiquement inutile.
Après pas mal d'efforts, en utilisant la méthode des variables contrôlées pour vérifier point par point, j'ai finalement identifié le vrai coupable —la dissipation thermique insuffisante à l'arrière de l'unité extérieure(bloquée par le panneau du meuble, la chaleur ne pouvait pas s'évacuer).

La solution temporaire envisagée était simple et brutale :pulvériser de l'eau sur l'unité extérieure avec une pompe pour forcer le refroidissement

Achat sur TB d'une pompe, de relais et autres modules, branchement à l'alimentation, ça fonctionne, première étape réussie !


Nouveau problème : pulvériser de l'eau en continu gaspille trop

L'interrupteur manuel est non seulement pénible, mais en l'absence de quelqu'un à la maison, soit ça tourne à sec, soit ça gaspille de l'eau.
J'ai commencé à réfléchir à comment faire en sorte que le systèmedémarre et s'arrête automatiquement selon la température

Je me suis soudain souvenu du capteur six axes MPU6050laissé de côté lors de la correction d'attitude de fusée l'année dernière.
Il intègre en interne un module de température NTC.
Bien qu'il soit à l'origine destiné à mesurer la température de la puce, le MPU6050 génère très peu de chaleur lui-même, on peut donc tout à fait l'assimiler à la température ambiante. Je l'ai donc « emprunté » à la fusée, associé à l'ESP32-C3


pour réaliser le contrôle de température.

Câblage matériel

Le câblage entre le MPU6050 et l'ESP32-C3 est très simple (à gauche : MPU6050, à droite : ESP32-C3) :Je l'ai donc « emprunté » à la fusée, associé à
MPU6050VCC
3V33V3
GNDSDA
P8 (SDA)SCL

P9 (SCL)

Conception logicielleEnvironnement de développement :
Arduino IDE

Idée principale : L'ESP32-C3 lance un serveur web léger ; une fois connecté depuis un téléphone ou un ordinateur, on peut voir la température en temps réel et l'état de l'arrosage, et contrôler manuellement ou activer l'automatisation via des boutons.

  • Fonctions principales : / Accès au chemin racine
  • Retourne la page de contrôle /dht
  • L'interface retourne les données du capteur (température en temps réel, état de l'arrosage, état automatique) Interface de bascule de l'arrosage (désactive simultanément le mode automatique)
  • /auto Interface de bascule du mode automatique
  • Logique d'automatisation : température ≥30℃ activation de l'eau, <30℃ arrêt de l'eau

Voici le code complet :

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);   // 端口80,可直接通过IP访问

// 网页 HTML(存储于 Flash)
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>空调浇水控制</title>
</head>
<body>
    <h2>空调浇水控制</h2>
    <div id="dht"></div>
    <button onclick="set()">开启/关闭浇水</button>
    <button onclick="autoset()">开启/关闭自动</button>
</body>
<script>
    function set() {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "/set?value=ESP32", true);
        xhr.send();
    }
    function autoset() {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "/auto?value=ESP32", true);
        xhr.send();
    }
    // 每秒更新一次数据
    setInterval(function () {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                document.getElementById("dht").innerHTML = this.responseText;
            }
        };
        xhttp.open("GET", "/dht", true);
        xhttp.send();
    }, 1000);
</script>
</html>
)rawliteral";

Adafruit_MPU6050 mpu;
#define MPU6050_INTERVAL 100       // 传感器读取间隔(毫秒)
unsigned long mpu6050Times = 0;
float mpu6050Temp = 0;

float xAcceleration, yAcceleration, zAcceleration;
float xAccele, yAccele, zAccele;
float xGyro = 0, yGyro = 0, zGyro = 0;
float gravity = 9.8;

bool iswater = false;  // 浇水状态
bool isauto = true;    // 自动模式默认开启

// 构造返回给网页的 HTML 数据
String Merge_Data(void) {
    String dataBuffer = "<p>";
    dataBuffer += "<h1>传感器数据</h1>";
    dataBuffer += "<b>温度: </b>";
    dataBuffer += String(mpu6050Temp, 1) + " ℃";
    dataBuffer += "<br />";
    dataBuffer += "<b>当前浇水状态: </b>";
    dataBuffer += iswater ? "开启" : "关闭";
    dataBuffer += "<br />";
    dataBuffer += "<b>当前自动状态: </b>";
    dataBuffer += isauto ? "开启" : "关闭";
    dataBuffer += "<br /></p>";
    return dataBuffer;
}

// 手动切换浇水(同时关闭自动模式)
void Config_Callback(AsyncWebServerRequest *request) {
    iswater = !iswater;
    isauto = false;
    request->send(200, "text/plain", "OK");
}

// 切换自动模式
void Auto_Callback(AsyncWebServerRequest *request) {
    isauto = !isauto;
    request->send(200, "text/plain", "OK");
}

void setup() {
    Serial.begin(115200);

    // 连接 WiFi(请替换为实际 SSID 和密码)
    WiFi.begin("你的WiFi名", "你的WiFi密码");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("正在连接WiFi...");
    }
    Serial.println("WiFi 连接成功!");
    Serial.print("IP 地址: ");
    Serial.println(WiFi.localIP());

    pinMode(1, OUTPUT);   // GPIO1 控制继电器(水泵)

    // 配置 Web 服务器路由
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send_P(200, "text/html", index_html);
    });
    server.on("/dht", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send_P(200, "text/plain", Merge_Data().c_str());
    });
    server.on("/set", HTTP_GET, Config_Callback);
    server.on("/auto", HTTP_GET, Auto_Callback);
    server.begin();
    Serial.println("HTTP 服务器已启动");

    // 初始化 MPU6050
    if (!mpu.begin()) {
        Serial.println("未找到 MPU6050 芯片!");
        while (1) { delay(1000); }  // 停止运行
    }
    mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
    mpu.setGyroRange(MPU6050_RANGE_250_DEG);
    mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
    Serial.println("MPU6050 初始化成功!");
}

void loop() {
    getMpu6050Data();   // 读取温度及姿态数据

    if (isauto) {
        // 自动模式:根据温度控制水泵
        if (mpu6050Temp >= 30.0) {
            digitalWrite(1, HIGH);
            iswater = true;
        } else {
            digitalWrite(1, LOW);
            iswater = false;
        }
    } else {
        // 手动模式:直接遵从按钮状态
        digitalWrite(1, iswater ? HIGH : LOW);
    }
}

void getMpu6050Data() {
    if (millis() - mpu6050Times >= MPU6050_INTERVAL) {
        mpu6050Times = millis();

        sensors_event_t a, g, temp;
        mpu.getEvent(&a, &g, &temp);

        mpu6050Temp = temp.temperature;

        xAcceleration = a.acceleration.x;
        yAcceleration = a.acceleration.y;
        zAcceleration = a.acceleration.z;

        xAccele = xAcceleration / gravity;   // 转换为 g 为单位
        yAccele = yAcceleration / gravity;
        zAccele = zAcceleration / gravity;

        xGyro = g.gyro.x;
        yGyro = g.gyro.y;
        zGyro = g.gyro.z;

        // 串口输出,便于调试(保留了姿态数据,方便后续扩展)
        Serial.print("温度: "); Serial.print(mpu6050Temp);
        Serial.print(" , x加速: "); Serial.print(xAccele);
        Serial.print(" , y加速: "); Serial.print(yAccele);
        Serial.print(" , z加速: "); Serial.print(zAccele);
        Serial.print(" , x角速度: "); Serial.print(xGyro);
        Serial.print(" , y角速度: "); Serial.print(yGyro);
        Serial.print(" , z角速度: "); Serial.println(zGyro);
    }
}