first commit

This commit is contained in:
kicap
2026-01-30 12:35:40 +08:00
commit 5c8342d836
9 changed files with 960 additions and 0 deletions

421
src/main.cpp Normal file
View File

@ -0,0 +1,421 @@
#include <Arduino.h>
// =====================================================
// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 (0.96" 128x64)
// Bahasa Indonesia | Stabil | Client-ready
// =====================================================
#define TINY_GSM_MODEM_SIM800
#define TINY_GSM_RX_BUFFER 650
#include <Wire.h>
#include <TinyGsmClient.h>
#include <MQUnifiedsensor.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ================== SERIAL ==================
#define SerialMon Serial
// ================== SIM800L =================
#define MODEM_RX 16 // ESP32 GPIO16 ← SIM800L TX
#define MODEM_TX 17 // ESP32 GPIO17 → SIM800L RX (via resistor)
HardwareSerial SerialAT(2);
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
// APN Indonesia (change if needed)
const char apn[] = "internet";
const char user[] = "";
const char pass[] = "";
// Server
const char server[] = "k-dummy.my.id";
const int port = 8080;
// ================= 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 ==================
void oledStatus(const String &msg)
{
display.clearDisplay();
display.setCursor(0, 0);
display.println("STATUS GSM:");
display.println(msg);
display.display();
}
// ================= 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);
}
// SIM800L UART
SerialMon.println("[GSM] Init UART...");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM INIT ...");
display.display();
SerialAT.begin(9600, SERIAL_8N1, MODEM_RX, MODEM_TX);
delay(3000);
SerialMon.println("[GSM] Restart modem...");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM RESTART modem...");
display.display();
if (!modem.restart())
{
SerialMon.println("[ERROR] Modem restart failed!");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM RESTART FAILED...");
display.display();
delay(1000);
while (1)
;
}
SerialMon.println("[GSM] Waiting for network...");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM WAIT NETWORK...");
display.display();
delay(2000);
if (!modem.waitForNetwork())
{
SerialMon.println("[ERROR] No network!");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM NO NETWORK...");
display.display();
delay(1000);
while (1)
;
}
SerialMon.println("[GSM] Network OK");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM NETWORK OK...");
display.display();
delay(2000);
SerialMon.println("[GSM] Connecting GPRS...");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM CONNECTING GPRS...");
display.display();
delay(2000);
if (!modem.gprsConnect(apn, user, pass))
{
SerialMon.println("[ERROR] GPRS failed!");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("");
display.display();
delay(1000);
while (1)
;
}
SerialMon.println("[GSM] GPRS CONNECTED");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("GSM GPRS CONNECTED...");
display.display();
delay(2000);
// MQ init
SerialMon.println("[MQ] Init MQ135 & MQ7");
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();
delay(2000);
// ================= 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);
if (client.connect(server, port))
{
String url = "/api/update?";
url += "co2=" + String(co2);
url += "&co=" + String(co);
url += "&bz=" + String(benzene);
url += "&aq=" + String(aq);
SerialMon.print("[HTTP] GET ");
SerialMon.println(url);
// Send request
client.print(String("GET ") + url + " HTTP/1.1\r\n");
client.print("Host: k-dummy.my.id\r\n");
client.print("Connection: close\r\n\r\n");
oledStatus("MENUNGGU RESP");
// -------------------------------
// READ RESPONSE
// -------------------------------
String response = "";
unsigned long timeout = millis();
while (client.connected() && millis() - timeout < 8000)
{
while (client.available())
{
char c = client.read();
response += c;
timeout = millis(); // reset timeout when data arrives
}
}
client.stop();
SerialMon.println("----- HTTP RESPONSE -----");
SerialMon.println(response);
SerialMon.println("-------------------------");
// -------------------------------
// EXTRACT JSON BODY
// -------------------------------
int jsonStart = response.indexOf('{');
if (jsonStart >= 0)
{
String json = response.substring(jsonStart);
SerialMon.print("[JSON] ");
SerialMon.println(json);
oledStatus("RESP OK");
}
else
{
SerialMon.println("[ERROR] No JSON found!");
oledStatus("RESP ERROR");
}
}
else
{
SerialMon.println("[ERROR] Server connection failed!");
oledStatus("GAGAL KIRIM");
}
client.stop();
SerialMon.println("===== LOOP END =====");
delay(10000);
}