#include #include #include // ----------- WiFi ----------- static const char* WIFI_SSID = "SSID"; static const char* WIFI_PASS = "PASS"; // ----------- DHT ----------- static const int DHT_PIN = 10; // GPIO for DHT DATA static const int DHT_TYPE = DHT22; // DHT11 / DHT22 / DHT12? DHT dht(DHT_PIN, DHT_TYPE); // ----------- MQ-135 ----------- static const int MQ_PIN = A2; // Analog pin for MQ-135 (GPIO2 on ESP32-C3) static const int MQ_ADC_CALIBRATION = 1900; // ADC baseline in clean air - ADJUST THIS static const float MQ_AQ_MIN = 0; // Min AQ value static const float MQ_AQ_MAX = 500; // Max AQ value (standard AQI scale) static const float MQ_ADC_MAX = 4095.0; // ESP32-C3 12-bit ADC max // ----------- Server ----------- WebServer server(80); // ----------- Reading interval ----------- static const unsigned long READ_MS = 2000; unsigned long lastRead = 0; // ----------- Latest values ----------- float latestH = NAN; float latestT_F = NAN; float latestAQ = NAN; // ----------- MQ-135 helper functions ----------- // Returns raw ADC average (multiple reads for stability) int readMQRaw() { long sum = 0; const int samples = 16; for (int i = 0; i < samples; i++) { sum += analogRead(MQ_PIN); delay(2); } return sum / samples; } // Maps raw ADC to a continuous AQ value (0–500 scale) // Higher ADC = more gas = worse air quality float readAirQuality() { int adc = readMQRaw(); // Map ADC range to AQ scale linearly. // MQ_ADC_CALIBRATION = your baseline in clean air. // Anything above that degrades air quality proportionally. // // Tune MQ_ADC_CALIBRATION by noting the ADC value in fresh air, // then setting it slightly below that number. int adcMin = MQ_ADC_CALIBRATION; // clean air baseline int adcMax = 4095; // sensor saturated // Linear interpolation between baseline (AQ=0) and saturation (AQ=500) float aq; if (adc <= adcMin) { aq = 0; } else { aq = ((float)(adc - adcMin) / (float)(adcMax - adcMin)) * 500.0; } aq = constrain(aq, 0.0, 500.0); return aq; } String htmlPage() { return R"HTML( ESP32 DHT+MQ

ESP32 DHT+MQ

Updates every 2 seconds • Last ~720 Samples • ~24 Hours

Temperature:

--

Humidity:

--

Air Quality:

--

--

Temp (°F)
Humidity (%)
Air Quality
)HTML"; } void handleRoot() { server.send(200, "text/html", htmlPage()); } void handleData() { // Convert NaN to null for easy JSON handling float h = latestH; float t = latestT_F; float aq = latestAQ; String json = "{"; json += "\"h\": " + (isnan(h) ? String("null") : String(h, 1)) + ","; json += "\"t_f\": " + (isnan(t) ? String("null") : String(t, 1)) + ","; json += "\"aq\": " + (isnan(aq) ? String("null") : String(aq, 1)); json += "}"; server.send(200, "application/json", json); } void setup() { Serial.begin(115200); delay(200); Serial.println("ESP32-C3 DHT11 + MQ-135 starting..."); dht.begin(); // Configure MQ-135 pin as analog input analogReadResolution(12); // 12-bit ADC (0-4095) WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); Serial.print("Connecting to WiFi"); while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); } Serial.println(); Serial.print("Connected. IP address: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/data", handleData); server.begin(); Serial.println("HTTP server started."); } void loop() { // keep server responsive server.handleClient(); unsigned long now = millis(); if (now - lastRead < READ_MS) return; lastRead = now; // Read DHT sensor float h = dht.readHumidity(); float tC = dht.readTemperature(); // Celsius // Read MQ-135 float aq = readAirQuality(); if (isnan(h) || isnan(tC)) { Serial.println("DHT read failed (check wiring/pull-up)."); latestH = NAN; latestT_F = NAN; } else { latestH = h; latestT_F = dht.convertCtoF(tC); // Already in F } latestAQ = aq; Serial.print("Humidity: "); Serial.print(latestH, 1); Serial.print(" %\tTemp: "); Serial.print(latestT_F, 1); Serial.print(" F\tAQ: "); Serial.print(latestAQ, 1); Serial.println(); Serial.print("Connected. IP address: "); Serial.println(WiFi.localIP()); }