花了周日一个下午把这个环境监测仪项目做完了,遇到不少坑,但这里没时间细谈,只能是把关键的正确部分信息记录下来。

硬件连接

注册部署免费MQTT服务器

https://cloud.emqx.com/

部署后,注意获取 mqtt_broker 地址,端口号(8883)并下载CA证书文件(后面要把证书内容复制到代码中)。

然后添加用户:

这里添加的用户名密码都是后面代码中,包括手机客户端中需要使用的。

编译上传代码

注意包含的库,如果缺失就在 arduino 库中寻找。例如 pubsubclient 就是 mqtt 通信需要的库。

完整代码如下,DIY的话注意自行修改配置:

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include "DHT.h"
#include <Wire.h>
#include <Adafruit_SGP30.h>

// 初始化 DHT 对象
#define DHTPIN 14
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// 定义SGP30实例
#define I2C_SDA 21 // 根据ESP32实际的SDA引脚定义
#define I2C_SCL 23 // 根据ESP32实际的SCL引脚定义
Adafruit_SGP30 sgp;

// WiFi settings
const char *ssid = "CMCC-abc";             // Replace with your WiFi name
const char *password = "abcd1234";   // Replace with your WiFi password

// MQTT Broker settings
const char *mqtt_broker = "fefe.ala.cn-hangzhou.emqxsl.cn";  // EMQX broker endpoint
const char *mqtt_topic = "env/sensor";     // MQTT topic  此为主题, 其它客户端订阅请使用 "env/#"
const char *topic_temp = "env/temperature";
const char *topic_humid = "env/humidity";
const char *topic_co2 = "env/CO2";
const char *topic_voc = "env/TVOC";
const char *mqtt_username = "test";  // MQTT username for authentication
const char *mqtt_password = "654321";  // MQTT password for authentication
const int mqtt_port = 8883;  // MQTT port (TLS)


// WiFi and MQTT client initialization
WiFiClientSecure espClient;
PubSubClient mqtt_client(espClient);

// SSL certificate for MQTT broker
static const char ca_cert[]
PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqXXDv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)EOF";


// Function declarations
void connectToWiFi();

void connectToMQTT();

void syncTime();

void mqttCallback(char *topic, byte *payload, unsigned int length);


uint32_t getAbsoluteHumidity(float temperature, float humidity) {
    // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
    const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
    const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
    return absoluteHumidityScaled;
}

void setup() {
    Serial.begin(115200);
    connectToWiFi();
    mqtt_client.setServer(mqtt_broker, mqtt_port);
    mqtt_client.setCallback(mqttCallback);
    connectToMQTT();
    // DHT
    Serial.println(F("DHT22 connected successfully!"));
    dht.begin();
  // 开始I2C通信
    Wire.begin(I2C_SDA, I2C_SCL);
    if (!sgp.begin(&Wire)) { 
        Serial.println("Failed to connect SGP30");
        while (true);   // 停在这里,直到连接成功
    }
    Serial.println("SGP30 connected successfully!");
}

void connectToWiFi() {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
}

void connectToMQTT() {
    espClient.setCACert(ca_cert);
    while (!mqtt_client.connected()) {
        String client_id = "esp32-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", client_id.c_str());
        if (mqtt_client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
            Serial.println("Connected to MQTT broker");
            mqtt_client.subscribe(mqtt_topic);
            // Publish message upon successful connection
            mqtt_client.publish(mqtt_topic, "Hi EMQX I'm ESP32 ^^");
        } else {
            // espClient.getLastSSLError(err_buf, sizeof(err_buf));
            Serial.print("Failed to connect to MQTT broker, rc=");
            Serial.println(mqtt_client.state());
            delay(5000);
        }
    }
}

void mqttCallback(char *topic, byte *payload, unsigned int length) {
    Serial.print("Message received on topic: ");
    Serial.print(topic);
    Serial.print("]: ");
    for (int i = 0; i < length; i++) {
        Serial.print((char) payload[i]);
    }
    Serial.println();
}

void loop() {
    if (!mqtt_client.connected()) {
        connectToMQTT();
    }
    mqtt_client.loop();

    // 读取湿度
    float humid = dht.readHumidity();
    // 读取温度
    float temp = dht.readTemperature();
    // 根据温湿度校正
    sgp.setHumidity(getAbsoluteHumidity(temp, humid));
    sgp.IAQmeasure();     
    // 读取和更新CO2与VOC值
    float eCO2 = sgp.eCO2;
    float TVOC = sgp.TVOC;

    // 显示内容
    Serial.print("湿度: ");
    Serial.print(humid);
    Serial.print("%, 温度: ");
    Serial.print(temp);
    Serial.print("°C,");
    Serial.print(" eCO2: ");
    Serial.print(eCO2);
    Serial.print(" ppm,");
    Serial.print(" TVOC: ");
    Serial.print(TVOC);
    Serial.println(" ppb,");

    // 发布内容
    char tempString[8];  
    dtostrf(temp, 5, 1, tempString); // 将温度转换为字符串,保留一位小数 
    String msg1 = String(tempString) + " °C"; // 整合数字和单位
    mqtt_client.publish(topic_temp, msg1.c_str());

    char humidString[8];  
    dtostrf(humid, 5, 1, humidString);  
    String msg2 = String(humidString) + " %";  
    mqtt_client.publish(topic_humid, msg2.c_str());

    char co2String[9];  
    dtostrf(eCO2, 7, 1, co2String);  
    String msg3 = String(co2String) + " ppm"; 
    mqtt_client.publish(topic_co2, msg3.c_str());

    char vocString[9];  
    dtostrf(TVOC, 7, 1, vocString);  
    String msg4 = String(vocString) + " ppb";  
    mqtt_client.publish(topic_voc, msg4.c_str());

    delay(5000);  //时间太长会掉线
}

下载手机客户端

到网上找了一个安卓 MQTT 客户端,简单进行配置,注意填写准确 broker 地址,端口号,加密选择 SSL,以及输入正确的用户名密码,就可以订阅这个环境监测传感器设备每隔 5 秒报送的数据主题了。注意MQTT订阅主题可以使用准确的 env/temperature 之类的,也可以使用通配符如 env/#

最后修改:2024 年 07 月 24 日
请大力赞赏以支持本站持续运行!