183 lines
4.7 KiB
Plaintext
183 lines
4.7 KiB
Plaintext
#include <Arduino.h>
|
|
// =====================================================
|
|
// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 (0.96" 128x64)
|
|
// Bahasa Indonesia | Stabil | Client-ready
|
|
// =====================================================
|
|
|
|
#include <Wire.h>
|
|
#include <MQUnifiedsensor.h>
|
|
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_SSD1306.h>
|
|
|
|
// ================= OLED CONFIG =================
|
|
#define SCREEN_WIDTH 128
|
|
#define SCREEN_HEIGHT 64
|
|
#define OLED_RESET -1
|
|
#define OLED_ADDR 0x3C
|
|
|
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
|
|
// ================= MQ CONFIG ===================
|
|
#define BOARD "ESP-32"
|
|
#define VOLTAGE 3.3
|
|
#define ADC_BITS 12
|
|
|
|
#define PIN_MQ135 34
|
|
#define PIN_MQ7 35
|
|
|
|
#define RATIO_CLEAN_MQ135 3.6
|
|
#define RATIO_CLEAN_MQ7 27.5
|
|
|
|
MQUnifiedsensor MQ135(BOARD, VOLTAGE, ADC_BITS, PIN_MQ135, "MQ-135");
|
|
MQUnifiedsensor MQ7(BOARD, VOLTAGE, ADC_BITS, PIN_MQ7, "MQ-7");
|
|
|
|
// ================= HELPER ======================
|
|
float readAverage(MQUnifiedsensor &sensor, int samples = 5) {
|
|
float sum = 0;
|
|
for (int i = 0; i < samples; i++) {
|
|
sensor.update();
|
|
sum += sensor.readSensor();
|
|
delay(50);
|
|
}
|
|
return sum / samples;
|
|
}
|
|
|
|
// =====================================================
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
delay(500);
|
|
|
|
// ================= OLED INIT =================
|
|
Wire.begin(21, 22);
|
|
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
|
|
Serial.println("❌ OLED tidak ditemukan!");
|
|
while (true) delay(1000);
|
|
}
|
|
|
|
display.clearDisplay();
|
|
display.setTextSize(1);
|
|
display.setTextColor(SSD1306_WHITE);
|
|
display.setCursor(0, 0);
|
|
display.println("Monitoring Udara");
|
|
display.println("ESP32 + MQ");
|
|
display.println("Kalibrasi...");
|
|
display.display();
|
|
|
|
// ================= KALIBRASI =================
|
|
Serial.println("Mulai kalibrasi sensor...");
|
|
Serial.println("Pastikan udara bersih (±1-2 menit)");
|
|
|
|
// MQ135
|
|
MQ135.setRegressionMethod(1);
|
|
MQ135.init();
|
|
float r0_135 = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
MQ135.update();
|
|
r0_135 += MQ135.calibrate(RATIO_CLEAN_MQ135);
|
|
delay(600);
|
|
}
|
|
r0_135 /= 10;
|
|
MQ135.setR0(r0_135);
|
|
|
|
// MQ7
|
|
MQ7.setRegressionMethod(1);
|
|
MQ7.init();
|
|
float r0_7 = 0;
|
|
for (int i = 0; i < 10; i++) {
|
|
MQ7.update();
|
|
r0_7 += MQ7.calibrate(RATIO_CLEAN_MQ7);
|
|
delay(600);
|
|
}
|
|
r0_7 /= 10;
|
|
MQ7.setR0(r0_7);
|
|
|
|
if (r0_135 <= 0 || r0_7 <= 0) {
|
|
Serial.println("❌ Kalibrasi gagal!");
|
|
display.clearDisplay();
|
|
display.setCursor(0, 0);
|
|
display.println("ERROR KALIBRASI");
|
|
display.display();
|
|
while (true) delay(1000);
|
|
}
|
|
|
|
Serial.println("Kalibrasi selesai!");
|
|
|
|
display.clearDisplay();
|
|
display.setCursor(0, 0);
|
|
display.println("Kalibrasi OK");
|
|
display.println("Mulai Monitor");
|
|
display.display();
|
|
delay(2000);
|
|
}
|
|
|
|
// =====================================================
|
|
void loop() {
|
|
|
|
// =============== MQ135 =================
|
|
MQ135.setA(110.47); MQ135.setB(-2.862);
|
|
float co2 = readAverage(MQ135);
|
|
if (co2 < 0) co2 = 0;
|
|
|
|
MQ135.setA(605.18); MQ135.setB(-3.937);
|
|
float benzene = readAverage(MQ135);
|
|
if (benzene < 0) benzene = 0;
|
|
|
|
// =============== MQ7 ===================
|
|
MQ7.setA(99.042); MQ7.setB(-1.518);
|
|
float co = readAverage(MQ7);
|
|
if (co < 0) co = 0;
|
|
|
|
// ========== AIR QUALITY ESTIMATION =====
|
|
int aq = 100;
|
|
|
|
if (co2 > 700) aq -= map(co2, 700, 2000, 0, 50);
|
|
if (co2 > 2000) aq -= map(co2, 2000, 5000, 50, 80);
|
|
|
|
if (co > 10) aq -= map(co, 10, 50, 0, 30);
|
|
if (co > 50) aq -= 30;
|
|
|
|
if (benzene > 5) aq -= map(benzene, 5, 50, 0, 40);
|
|
|
|
aq = constrain(aq, 0, 100);
|
|
|
|
String status;
|
|
if (aq >= 90) status = "Sangat Baik";
|
|
else if (aq >= 70) status = "Baik";
|
|
else if (aq >= 50) status = "Sedang";
|
|
else if (aq >= 30) status = "Buruk";
|
|
else status = "Sangat Buruk";
|
|
|
|
// =============== OLED DISPLAY ==========
|
|
display.clearDisplay();
|
|
display.setCursor(0, 0);
|
|
|
|
display.print("CO2: ");
|
|
display.print(co2, 0);
|
|
display.println(" ppm");
|
|
|
|
display.print("CO : ");
|
|
display.print(co, 1);
|
|
display.println(" ppm");
|
|
|
|
display.print("BZ : ");
|
|
display.print(benzene, 1);
|
|
display.println(" ppm");
|
|
|
|
display.print("AQ : ");
|
|
display.print(aq);
|
|
display.print("% ");
|
|
display.println(status);
|
|
|
|
display.display();
|
|
|
|
// =============== SERIAL =================
|
|
Serial.println("===== STATUS UDARA =====");
|
|
Serial.print("CO2 : "); Serial.print(co2); Serial.println(" ppm");
|
|
Serial.print("CO : "); Serial.print(co); Serial.println(" ppm");
|
|
Serial.print("BZ : "); Serial.print(benzene); Serial.println(" ppm");
|
|
Serial.print("AQ : "); Serial.print(aq); Serial.print("% "); Serial.println(status);
|
|
Serial.println("========================\n");
|
|
|
|
delay(5000);
|
|
}
|