From d5625acd39318df79dddeec70c72334c98ec41b5 Mon Sep 17 00:00:00 2001 From: kicap Date: Sun, 27 Sep 2026 09:07:39 +0800 Subject: [PATCH] added gps for cordinate changes --- .vscode/extensions.json | 3 +- platformio.ini | 3 +- src/main.cpp | 190 ++++++++------- src/main.cpp.again | 512 ++++++++++++++++++++++++++++++++++++++++ src/main.cpp.great | 477 +++++++++++++++++++++++++++++++++++++ src/main.cpp.testgps | 104 ++++++++ 6 files changed, 1204 insertions(+), 85 deletions(-) create mode 100644 src/main.cpp.again create mode 100644 src/main.cpp.great create mode 100644 src/main.cpp.testgps diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 080e70d..a91ca8f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,6 +5,7 @@ "platformio.platformio-ide" ], "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" + "ms-vscode.cpptools-extension-pack", + "pioarduino.pioarduino-ide" ] } diff --git a/platformio.ini b/platformio.ini index ac8bd16..de665cb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,5 +16,6 @@ lib_deps = miguel5612/MQUnifiedsensor@^3.0.5 adafruit/Adafruit SSD1306@^2.5.16 adafruit/Adafruit GFX Library@^1.12.4 - vshymanskyy/TinyGSM@^0.12.0 + ; vshymanskyy/TinyGSM@^0.12.0 + mikalhart/TinyGPSPlus@^1.1.0 monitor_speed = 115200 diff --git a/src/main.cpp b/src/main.cpp index 6e8410a..35808be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #include // ===================================================== -// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 (0.96" 128x64) +// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 + GPS (BN-220) // WiFi Version // ===================================================== @@ -10,6 +10,7 @@ #include #include #include +#include // ================== WIFI ================== const char* ssid = "KARAN"; @@ -27,6 +28,14 @@ const int port = 80; Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); +// ================= GPS CONFIG ================== +static const int GPS_RX_PIN = 16; // GPS TX -> ESP32 GPIO 16 +static const int GPS_TX_PIN = 17; // GPS RX -> ESP32 GPIO 17 +static const uint32_t GPS_BAUD = 9600; + +TinyGPSPlus gps; +HardwareSerial gpsSerial(2); + // ================= MQ CONFIG =================== #define BOARD "ESP-32" #define VOLTAGE 3.3 @@ -79,6 +88,43 @@ void oledMQStatus( delay(500); } +// =============== GPS HELPERS =================== + +// Feed any pending GPS data to the library (non-blocking) +void updateGPS() +{ + while (gpsSerial.available() > 0) + { + gps.encode(gpsSerial.read()); + } +} + +// Returns "lat,lng" if a valid fix exists, otherwise "-" +String getGPSCoordinates() +{ + updateGPS(); + + if (gps.location.isValid() && gps.location.age() < 2000) + { + return String(gps.location.lat(), 6) + "," + + String(gps.location.lng(), 6); + } + + return "-"; +} + +// Returns a status string for the OLED +String getGPSStatus() +{ + if (gps.charsProcessed() < 10) + return "NO DATA"; + + if (gps.location.isValid() && gps.location.age() < 2000) + return "FIX " + String(gps.satellites.value()) + " sats"; + + return "NO FIX"; +} + // ================= HELPER ====================== float readAverage(MQUnifiedsensor &sensor, int samples = 5) { @@ -88,6 +134,8 @@ float readAverage(MQUnifiedsensor &sensor, int samples = 5) { sensor.update(); sum += sensor.readSensor(); + + updateGPS(); // keep GPS buffer drained during sampling delay(50); } @@ -144,9 +192,7 @@ bool connectWiFi() bool ensureWiFi() { if (WiFi.status() == WL_CONNECTED) - { return true; - } Serial.println("[WiFi] Connection lost!"); oledWiFiStatus("WIFI PUTUS"); @@ -163,6 +209,10 @@ void setup() Serial.begin(115200); delay(500); + // ================= GPS INIT ================== + gpsSerial.begin(GPS_BAUD, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); + Serial.println("[GPS] Serial initialized on GPIO16/17"); + // ================= OLED INIT ================= Wire.begin(21, 22); @@ -170,9 +220,7 @@ void setup() if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { Serial.println("OLED tidak ditemukan!"); - - while (true) - delay(1000); + while (true) delay(1000); } // ================= WIFI INIT ================= @@ -182,11 +230,8 @@ void setup() if (!connectWiFi()) { Serial.println("[ERROR] WiFi gagal!"); - oledWiFiStatus("RESTART ESP32"); - delay(2000); - ESP.restart(); } @@ -215,14 +260,12 @@ void setup() for (int i = 0; i < 10; i++) { MQ135.update(); - r0_135 += MQ135.calibrate(RATIO_CLEAN_MQ135); - + updateGPS(); // keep GPS data flowing delay(600); } r0_135 /= 10; - MQ135.setR0(r0_135); // ================= MQ7 ================= @@ -235,14 +278,12 @@ void setup() for (int i = 0; i < 10; i++) { MQ7.update(); - r0_7 += MQ7.calibrate(RATIO_CLEAN_MQ7); - + updateGPS(); delay(600); } r0_7 /= 10; - MQ7.setR0(r0_7); // ================= CHECK CALIBRATION ================= @@ -250,32 +291,18 @@ void setup() if (r0_135 <= 0 || r0_7 <= 0) { Serial.println("Kalibrasi gagal!"); - - oledMQStatus( - "KALIBRASI GAGAL", - "", - "", - "RESTART ESP32..."); - + oledMQStatus("KALIBRASI GAGAL", "", "", "RESTART ESP32..."); delay(2000); - ESP.restart(); } Serial.println("Kalibrasi selesai!"); - Serial.print("MQ135 R0 = "); Serial.println(r0_135); - Serial.print("MQ7 R0 = "); Serial.println(r0_7); - oledMQStatus( - "KALIBRASI OK", - "...", - "Mulai Monitoring", - "..."); - + oledMQStatus("KALIBRASI OK", "...", "Mulai Monitoring", "..."); delay(1000); } @@ -291,11 +318,8 @@ void loop() if (!ensureWiFi()) { Serial.println("[WiFi] Recover failed!"); - oledWiFiStatus("WIFI ERROR"); - delay(5000); - return; } @@ -303,31 +327,20 @@ void loop() MQ135.setA(110.47); MQ135.setB(-2.862); - float co2 = readAverage(MQ135); - - if (co2 < 0) - co2 = 0; - - // ================================================= + if (co2 < 0) co2 = 0; MQ135.setA(605.18); MQ135.setB(-3.937); - float benzene = readAverage(MQ135); - - if (benzene < 0) - benzene = 0; + if (benzene < 0) benzene = 0; // =============== MQ7 =================== MQ7.setA(99.042); MQ7.setB(-1.518); - float co = readAverage(MQ7); - - if (co < 0) - co = 0; + if (co < 0) co = 0; // ========== AIR QUALITY ESTIMATION ===== @@ -335,16 +348,12 @@ void loop() 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); @@ -353,49 +362,71 @@ void loop() // ================= STATUS ================= 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"; - 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"; + // =============== GPS READ ================== + + String gps_coords = getGPSCoordinates(); + String gps_status = getGPSStatus(); // =============== OLED DISPLAY ========== + // 6 lines fit on 128x64 with textSize(1) + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); - oledMQStatus( - "CO2 : " + String(co2) + " ppm", - "CO : " + String(co) + " ppm", - "BZ : " + String(benzene) + " ppm", - "AQ : " + String(aq) + " % ", - status); + display.println("CO2:" + String(co2, 1) + " CO:" + String(co, 1)); + display.println("BZ :" + String(benzene, 1) + " AQ:" + String(aq) + "%"); + display.println(status); + display.println("GPS: " + gps_status); + + String lat = "-3.9891687826423334"; + String lng = "119.65221465458342"; + + if (gps_coords != "-") + { + // Split lat/lng to two lines for readability + int commaIdx = gps_coords.indexOf(','); + display.println("Lat:" + gps_coords.substring(0, commaIdx)); + display.println("Lng:" + gps_coords.substring(commaIdx + 1)); + + lat = gps_coords.substring(0, commaIdx); + lng = gps_coords.substring(commaIdx + 1); + + } + else + { + display.println("Lat: -"); + display.println("Lng: -"); + } + + 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.print("GPS : "); + Serial.println(gps_coords); + Serial.print("GPS status: "); + Serial.println(gps_status); Serial.println("========================\n"); delay(5000); @@ -409,12 +440,13 @@ void loop() HTTPClient http; String url = String(server) + "/api/update?"; - url += "co2=" + String(co2); url += "&co=" + String(co); url += "&bz=" + String(benzene); url += "&aq=" + String(aq); url += "&id=2"; + url += "&lat=" + lat; + url += "&lng=" + lng; Serial.print("[HTTP] GET "); Serial.println(url); @@ -422,7 +454,6 @@ void loop() oledWiFiStatus("MENGIRIM DATA..."); http.begin(url); - int httpCode = http.GET(); if (httpCode > 0) @@ -431,26 +462,21 @@ void loop() Serial.println(httpCode); String response = http.getString(); - Serial.println("----- HTTP RESPONSE -----"); Serial.println(response); Serial.println("-------------------------"); int jsonStart = response.indexOf('{'); - if (jsonStart >= 0) { String json = response.substring(jsonStart); - Serial.print("[JSON] "); Serial.println(json); - oledWiFiStatus("RESP OK"); } else { Serial.println("[ERROR] No JSON found!"); - oledWiFiStatus("RESP ERROR"); } } @@ -458,7 +484,6 @@ void loop() { Serial.print("[ERROR] HTTP failed: "); Serial.println(http.errorToString(httpCode)); - oledWiFiStatus("GAGAL KIRIM"); } @@ -467,7 +492,6 @@ void loop() else { Serial.println("[ERROR] WiFi disconnected!"); - oledWiFiStatus("WIFI PUTUS"); } diff --git a/src/main.cpp.again b/src/main.cpp.again new file mode 100644 index 0000000..de641ec --- /dev/null +++ b/src/main.cpp.again @@ -0,0 +1,512 @@ +#include +// ===================================================== +// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 + GPS (BN-220) +// WiFi Version +// ===================================================== + +#include +#include +#include +#include +#include +#include +#include + +// ================== WIFI ================== +const char* ssid = "KARAN"; +const char* password = "12345679"; + +// Server +const char server[] = "http://leman.k-dummy.my.id"; +const int port = 80; + +// ================= 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); + +// ================= GPS CONFIG ================== +static const int GPS_RX_PIN = 16; // GPS TX -> ESP32 GPIO 16 +static const int GPS_TX_PIN = 17; // GPS RX -> ESP32 GPIO 17 +static const uint32_t GPS_BAUD = 9600; + +TinyGPSPlus gps; +HardwareSerial gpsSerial(2); + +// ================= 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 oledWiFiStatus(const String &msg) +{ + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); + + display.println("STATUS WIFI:"); + display.println(msg); + + display.display(); + delay(500); +} + +void oledMQStatus( + const String &msg1, + const String &msg2, + const String &msg3, + const String &msg4, + String msg5 = "") +{ + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); + + display.println("MQ STATUS:"); + display.println(msg1); + display.println(msg2); + display.println(msg3); + display.println(msg4); + display.println(msg5); + + display.display(); + delay(500); +} + +// =============== GPS HELPER ==================== + +// Feed any pending GPS data to the library (non-blocking) +void updateGPS() +{ + while (gpsSerial.available() > 0) + { + gps.encode(gpsSerial.read()); + } +} + +// Returns "lat,lng" if a valid fix exists, otherwise "-" +String getGPSCoordinates() +{ + updateGPS(); // always drain the buffer + oledWiFiStatus("GPS: mencari koordinat..."); + Serial.println("[GPS] Mencari koordinat..."); + delay(2000); + + if (gps.location.isValid() && + gps.location.age() < 2000) // fix must be < 2s old + { + oledWiFiStatus("GPS: koordinat ditemukan"); + Serial.println("[GPS] Koordinat ditemukan"); + delay(1000); + oledWiFiStatus("GPS: " + String(gps.location.lat(), 6) + "," + String(gps.location.lng(), 6)); + Serial.println("[GPS] Koordinat: " + String(gps.location.lat(), 6) + "," + String(gps.location.lng(), 6)); + delay(2000); + + return String(gps.location.lat(), 6) + "," + + String(gps.location.lng(), 6); + } + + oledWiFiStatus("GPS: koordinat tidak ditemukan"); + Serial.println("[GPS] Koordinat tidak ditemukan"); + delay(2000); + + return "-"; +} + +// Returns "8 sats" or "no fix" for OLED display +String getGPSStatus() +{ + if (gps.location.isValid() && gps.location.age() < 2000) + { + return String(gps.satellites.value()) + " sats"; + } + return "no fix"; +} + +// ================= HELPER ====================== +float readAverage(MQUnifiedsensor &sensor, int samples = 5) +{ + float sum = 0; + + for (int i = 0; i < samples; i++) + { + sensor.update(); + sum += sensor.readSensor(); + + updateGPS(); // keep GPS buffer drained during sampling + delay(50); + } + + return sum / samples; +} + +// ===================================================== +// WIFI CONNECTION +// ===================================================== +bool connectWiFi() +{ + Serial.println("[WiFi] Connecting..."); + Serial.print("[WiFi] SSID: "); + Serial.println(ssid); + + oledWiFiStatus("Menghubungkan..."); + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + + unsigned long startAttempt = millis(); + + while (WiFi.status() != WL_CONNECTED && + millis() - startAttempt < 30000) + { + delay(500); + Serial.print("."); + } + + Serial.println(); + + if (WiFi.status() == WL_CONNECTED) + { + Serial.println("[WiFi] CONNECTED"); + Serial.print("[WiFi] IP: "); + Serial.println(WiFi.localIP()); + + oledWiFiStatus("WIFI TERHUBUNG"); + + delay(1000); + + return true; + } + + Serial.println("[WiFi] Connection failed!"); + oledWiFiStatus("WIFI GAGAL"); + + return false; +} + +// ===================================================== +// ENSURE WIFI +// ===================================================== +bool ensureWiFi() +{ + if (WiFi.status() == WL_CONNECTED) + { + return true; + } + + Serial.println("[WiFi] Connection lost!"); + oledWiFiStatus("WIFI PUTUS"); + + WiFi.disconnect(); + delay(1000); + + return connectWiFi(); +} + +// ===================================================== +void setup() +{ + Serial.begin(115200); + delay(500); + + // ================= GPS INIT ================== + gpsSerial.begin(GPS_BAUD, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); + Serial.println("[GPS] Serial initialized on GPIO16/17"); + + // ================= OLED INIT ================= + + Wire.begin(21, 22); + + if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) + { + Serial.println("OLED tidak ditemukan!"); + + while (true) + delay(1000); + } + + // ================= WIFI INIT ================= + + Serial.println("[WiFi] Init WiFi..."); + + if (!connectWiFi()) + { + Serial.println("[ERROR] WiFi gagal!"); + + oledWiFiStatus("RESTART ESP32"); + + delay(2000); + + ESP.restart(); + } + + // ================= MQ INIT ================= + + Serial.println("[MQ] Init MQ135 & MQ7"); + + oledMQStatus( + "Init MQ135 & MQ7", + "Mulai kalibrasi sensor...", + "Pastikan udara bersih", + "(±1-2 menit)"); + + // ================= 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); + updateGPS(); // keep GPS data flowing + 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); + updateGPS(); // keep GPS data flowing + delay(600); + } + + r0_7 /= 10; + MQ7.setR0(r0_7); + + // ================= CHECK CALIBRATION ================= + + if (r0_135 <= 0 || r0_7 <= 0) + { + Serial.println("Kalibrasi gagal!"); + + oledMQStatus("KALIBRASI GAGAL", "", "", "RESTART ESP32..."); + + delay(2000); + + ESP.restart(); + } + + Serial.println("Kalibrasi selesai!"); + Serial.print("MQ135 R0 = "); + Serial.println(r0_135); + Serial.print("MQ7 R0 = "); + Serial.println(r0_7); + + oledMQStatus("KALIBRASI OK", "...", "Mulai Monitoring", "..."); + + delay(1000); +} + +// ===================================================== +// LOOP +// ===================================================== +void loop() +{ + // =================================================== + // CHECK WIFI + // =================================================== + + if (!ensureWiFi()) + { + Serial.println("[WiFi] Recover failed!"); + oledWiFiStatus("WIFI ERROR"); + delay(5000); + return; + } + + // =============== 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); + + // ================= STATUS ================= + + 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"; + + // =============== GPS READ ================== + + String gps_coords = getGPSCoordinates(); // "lat,lng" or "-" + String gps_status = getGPSStatus(); // "8 sats" or "no fix" + + // =============== OLED DISPLAY ========== + + // Compact display: AQ + GPS on one screen + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); + + display.println("CO2 : " + String(co2, 1) + " ppm"); + display.println("CO : " + String(co, 1) + " ppm"); + display.println("BZ : " + String(benzene, 1) + " ppm"); + display.println("AQ : " + String(aq) + "% " + status); + display.println("GPS : " + gps_status); + display.println(gps_coords); + + 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.print("GPS : "); + Serial.println(gps_coords); + Serial.print("GPS status: "); + Serial.println(gps_status); + Serial.println("========================\n"); + + delay(5000); + + // ================================================= + // HTTP REQUEST + // ================================================= + + if (WiFi.status() == WL_CONNECTED) + { + HTTPClient http; + + String url = String(server) + "/api/update?"; + url += "co2=" + String(co2); + url += "&co=" + String(co); + url += "&bz=" + String(benzene); + url += "&aq=" + String(aq); + url += "&id=2"; + url += "&gps=" + gps_coords; + + Serial.print("[HTTP] GET "); + Serial.println(url); + + oledWiFiStatus("MENGIRIM DATA..."); + + http.begin(url); + int httpCode = http.GET(); + + if (httpCode > 0) + { + Serial.print("[HTTP] Response code: "); + Serial.println(httpCode); + + String response = http.getString(); + Serial.println("----- HTTP RESPONSE -----"); + Serial.println(response); + Serial.println("-------------------------"); + + int jsonStart = response.indexOf('{'); + if (jsonStart >= 0) + { + String json = response.substring(jsonStart); + Serial.print("[JSON] "); + Serial.println(json); + oledWiFiStatus("RESP OK"); + } + else + { + Serial.println("[ERROR] No JSON found!"); + oledWiFiStatus("RESP ERROR"); + } + } + else + { + Serial.print("[ERROR] HTTP failed: "); + Serial.println(http.errorToString(httpCode)); + oledWiFiStatus("GAGAL KIRIM"); + } + + http.end(); + } + else + { + Serial.println("[ERROR] WiFi disconnected!"); + oledWiFiStatus("WIFI PUTUS"); + } + + Serial.println("===== LOOP END ====="); + + delay(10000); +} \ No newline at end of file diff --git a/src/main.cpp.great b/src/main.cpp.great new file mode 100644 index 0000000..3d13a88 --- /dev/null +++ b/src/main.cpp.great @@ -0,0 +1,477 @@ +#include +// ===================================================== +// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 (0.96" 128x64) +// WiFi Version +// ===================================================== + +#include +#include +#include +#include +#include +#include + +// ================== WIFI ================== +const char* ssid = "Nare"; +const char* password = "0987654321"; + +// Server +const char server[] = "http://leman.k-dummy.my.id"; +const int port = 80; + +// ================= 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 oledWiFiStatus(const String &msg) +{ + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); + + display.println("STATUS WIFI:"); + display.println(msg); + + display.display(); + delay(500); +} + +void oledMQStatus( + const String &msg1, + const String &msg2, + const String &msg3, + const String &msg4, + String msg5 = "") +{ + display.clearDisplay(); + display.setTextSize(1); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); + + display.println("MQ STATUS:"); + display.println(msg1); + display.println(msg2); + display.println(msg3); + display.println(msg4); + display.println(msg5); + + display.display(); + delay(500); +} + +// ================= 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; +} + +// ===================================================== +// WIFI CONNECTION +// ===================================================== +bool connectWiFi() +{ + Serial.println("[WiFi] Connecting..."); + Serial.print("[WiFi] SSID: "); + Serial.println(ssid); + + oledWiFiStatus("Menghubungkan..."); + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + + unsigned long startAttempt = millis(); + + while (WiFi.status() != WL_CONNECTED && + millis() - startAttempt < 30000) + { + delay(500); + Serial.print("."); + } + + Serial.println(); + + if (WiFi.status() == WL_CONNECTED) + { + Serial.println("[WiFi] CONNECTED"); + Serial.print("[WiFi] IP: "); + Serial.println(WiFi.localIP()); + + oledWiFiStatus("WIFI TERHUBUNG"); + + delay(1000); + + return true; + } + + Serial.println("[WiFi] Connection failed!"); + oledWiFiStatus("WIFI GAGAL"); + + return false; +} + +// ===================================================== +// ENSURE WIFI +// ===================================================== +bool ensureWiFi() +{ + if (WiFi.status() == WL_CONNECTED) + { + return true; + } + + Serial.println("[WiFi] Connection lost!"); + oledWiFiStatus("WIFI PUTUS"); + + WiFi.disconnect(); + delay(1000); + + return connectWiFi(); +} + +// ===================================================== +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); + } + + // ================= WIFI INIT ================= + + Serial.println("[WiFi] Init WiFi..."); + + if (!connectWiFi()) + { + Serial.println("[ERROR] WiFi gagal!"); + + oledWiFiStatus("RESTART ESP32"); + + delay(2000); + + ESP.restart(); + } + + // ================= MQ INIT ================= + + Serial.println("[MQ] Init MQ135 & MQ7"); + + oledMQStatus( + "Init MQ135 & MQ7", + "Mulai kalibrasi sensor...", + "Pastikan udara bersih", + "(±1-2 menit)"); + + // ================= 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); + + // ================= CHECK CALIBRATION ================= + + if (r0_135 <= 0 || r0_7 <= 0) + { + Serial.println("Kalibrasi gagal!"); + + oledMQStatus( + "KALIBRASI GAGAL", + "", + "", + "RESTART ESP32..."); + + delay(2000); + + ESP.restart(); + } + + Serial.println("Kalibrasi selesai!"); + + Serial.print("MQ135 R0 = "); + Serial.println(r0_135); + + Serial.print("MQ7 R0 = "); + Serial.println(r0_7); + + oledMQStatus( + "KALIBRASI OK", + "...", + "Mulai Monitoring", + "..."); + + delay(1000); +} + +// ===================================================== +// LOOP +// ===================================================== +void loop() +{ + // =================================================== + // CHECK WIFI + // =================================================== + + if (!ensureWiFi()) + { + Serial.println("[WiFi] Recover failed!"); + + oledWiFiStatus("WIFI ERROR"); + + delay(5000); + + return; + } + + // =============== 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); + + // ================= STATUS ================= + + 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 ========== + + oledMQStatus( + "CO2 : " + String(co2) + " ppm", + "CO : " + String(co) + " ppm", + "BZ : " + String(benzene) + " ppm", + "AQ : " + String(aq) + " % ", + status); + + // =============== 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); + + // ================================================= + // HTTP REQUEST + // ================================================= + + if (WiFi.status() == WL_CONNECTED) + { + HTTPClient http; + + String url = String(server) + "/api/update?"; + + url += "co2=" + String(co2); + url += "&co=" + String(co); + url += "&bz=" + String(benzene); + url += "&aq=" + String(aq); + url += "&id=2"; + + Serial.print("[HTTP] GET "); + Serial.println(url); + + oledWiFiStatus("MENGIRIM DATA..."); + + http.begin(url); + + int httpCode = http.GET(); + + if (httpCode > 0) + { + Serial.print("[HTTP] Response code: "); + Serial.println(httpCode); + + String response = http.getString(); + + Serial.println("----- HTTP RESPONSE -----"); + Serial.println(response); + Serial.println("-------------------------"); + + int jsonStart = response.indexOf('{'); + + if (jsonStart >= 0) + { + String json = response.substring(jsonStart); + + Serial.print("[JSON] "); + Serial.println(json); + + oledWiFiStatus("RESP OK"); + } + else + { + Serial.println("[ERROR] No JSON found!"); + + oledWiFiStatus("RESP ERROR"); + } + } + else + { + Serial.print("[ERROR] HTTP failed: "); + Serial.println(http.errorToString(httpCode)); + + oledWiFiStatus("GAGAL KIRIM"); + } + + http.end(); + } + else + { + Serial.println("[ERROR] WiFi disconnected!"); + + oledWiFiStatus("WIFI PUTUS"); + } + + Serial.println("===== LOOP END ====="); + + delay(10000); +} \ No newline at end of file diff --git a/src/main.cpp.testgps b/src/main.cpp.testgps new file mode 100644 index 0000000..bd42ff8 --- /dev/null +++ b/src/main.cpp.testgps @@ -0,0 +1,104 @@ +#include + +// ---- Pin Configuration ---- +static const int RXPin = 16; // GPS TX -> ESP32 RX +static const int TXPin = 17; // GPS RX -> ESP32 TX +static const uint32_t GPSBaud = 9600; + +TinyGPSPlus gps; +HardwareSerial gpsSerial(2); + +// ---- Timing ---- +unsigned long lastStatusPrint = 0; +const unsigned long STATUS_INTERVAL = 1000; // print every 1 second + +void setup() { + Serial.begin(115200); + delay(3000); // Critical: allow USB serial to stabilize + + Serial.println(); + Serial.println(F("========================================")); + Serial.println(F(" ESP32 + GPS Coordinate Tracker")); + Serial.println(F("========================================")); + Serial.print(F("RX Pin: GPIO ")); Serial.println(RXPin); + Serial.print(F("TX Pin: GPIO ")); Serial.println(TXPin); + Serial.print(F("Baud: ")); Serial.println(GPSBaud); + Serial.println(F("----------------------------------------")); + + gpsSerial.begin(GPSBaud, SERIAL_8N1, RXPin, TXPin); + + Serial.println(F("Status: Waiting for fix... (go outside)")); + Serial.println(F("========================================")); + Serial.println(); +} + +void printTime() { + if (!gps.time.isValid()) { + Serial.print(F("--:--:--")); + return; + } + if (gps.time.hour() < 10) Serial.print(F("0")); + Serial.print(gps.time.hour()); + Serial.print(F(":")); + if (gps.time.minute() < 10) Serial.print(F("0")); + Serial.print(gps.time.minute()); + Serial.print(F(":")); + if (gps.time.second() < 10) Serial.print(F("0")); + Serial.print(gps.time.second()); +} +void printStatus() { + // ---- Check if GPS is communicating at all ---- + if (gps.charsProcessed() < 10) { + Serial.println(F("[!] No GPS data. Check wiring/power/baud.")); + return; + } + + // ---- If we have a valid fix, print full details ---- + if (gps.location.isValid()) { + Serial.print(F("LAT: ")); + Serial.print(gps.location.lat(), 6); + Serial.print(F(" LNG: ")); + Serial.print(gps.location.lng(), 6); + + Serial.print(F(" SATS: ")); + Serial.print(gps.satellites.isValid() ? gps.satellites.value() : 0); + + Serial.print(F(" ALT: ")); + Serial.print(gps.altitude.isValid() ? gps.altitude.meters() : 0.0, 1); + Serial.print(F("m")); + + Serial.print(F(" SPD: ")); + Serial.print(gps.speed.isValid() ? gps.speed.kmph() : 0.0, 1); + Serial.print(F("km/h")); + + Serial.print(F(" HDOP: ")); + Serial.print(gps.hdop.isValid() ? gps.hdop.hdop() : 0.0, 1); + + Serial.print(F(" UTC: ")); + printTime(); + + Serial.println(); + } + // ---- No fix yet, but GPS is alive ---- + else { + Serial.print(F("[...] GPS alive. Chars: ")); + Serial.print(gps.charsProcessed()); + Serial.print(F(" Sats in view: ")); + Serial.print(gps.satellites.isValid() ? gps.satellites.value() : 0); + Serial.println(F(" Waiting for lock...")); + } +} + + +void loop() { + // Feed all available GPS data to the library + while (gpsSerial.available() > 0) { + gps.encode(gpsSerial.read()); + } + + // Print status at regular intervals + if (millis() - lastStatusPrint >= STATUS_INTERVAL) { + lastStatusPrint = millis(); + printStatus(); + } +}