added gps for cordinate changes
This commit is contained in:
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -5,6 +5,7 @@
|
|||||||
"platformio.platformio-ide"
|
"platformio.platformio-ide"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
"ms-vscode.cpptools-extension-pack"
|
"ms-vscode.cpptools-extension-pack",
|
||||||
|
"pioarduino.pioarduino-ide"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,5 +16,6 @@ lib_deps =
|
|||||||
miguel5612/MQUnifiedsensor@^3.0.5
|
miguel5612/MQUnifiedsensor@^3.0.5
|
||||||
adafruit/Adafruit SSD1306@^2.5.16
|
adafruit/Adafruit SSD1306@^2.5.16
|
||||||
adafruit/Adafruit GFX Library@^1.12.4
|
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
|
monitor_speed = 115200
|
||||||
|
|||||||
190
src/main.cpp
190
src/main.cpp
@ -1,6 +1,6 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 (0.96" 128x64)
|
// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 + GPS (BN-220)
|
||||||
// WiFi Version
|
// WiFi Version
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
@ -10,6 +10,7 @@
|
|||||||
#include <MQUnifiedsensor.h>
|
#include <MQUnifiedsensor.h>
|
||||||
#include <Adafruit_GFX.h>
|
#include <Adafruit_GFX.h>
|
||||||
#include <Adafruit_SSD1306.h>
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include <TinyGPSPlus.h>
|
||||||
|
|
||||||
// ================== WIFI ==================
|
// ================== WIFI ==================
|
||||||
const char* ssid = "KARAN";
|
const char* ssid = "KARAN";
|
||||||
@ -27,6 +28,14 @@ const int port = 80;
|
|||||||
|
|
||||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
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 ===================
|
// ================= MQ CONFIG ===================
|
||||||
#define BOARD "ESP-32"
|
#define BOARD "ESP-32"
|
||||||
#define VOLTAGE 3.3
|
#define VOLTAGE 3.3
|
||||||
@ -79,6 +88,43 @@ void oledMQStatus(
|
|||||||
delay(500);
|
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 ======================
|
// ================= HELPER ======================
|
||||||
float readAverage(MQUnifiedsensor &sensor, int samples = 5)
|
float readAverage(MQUnifiedsensor &sensor, int samples = 5)
|
||||||
{
|
{
|
||||||
@ -88,6 +134,8 @@ float readAverage(MQUnifiedsensor &sensor, int samples = 5)
|
|||||||
{
|
{
|
||||||
sensor.update();
|
sensor.update();
|
||||||
sum += sensor.readSensor();
|
sum += sensor.readSensor();
|
||||||
|
|
||||||
|
updateGPS(); // keep GPS buffer drained during sampling
|
||||||
delay(50);
|
delay(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,9 +192,7 @@ bool connectWiFi()
|
|||||||
bool ensureWiFi()
|
bool ensureWiFi()
|
||||||
{
|
{
|
||||||
if (WiFi.status() == WL_CONNECTED)
|
if (WiFi.status() == WL_CONNECTED)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
Serial.println("[WiFi] Connection lost!");
|
Serial.println("[WiFi] Connection lost!");
|
||||||
oledWiFiStatus("WIFI PUTUS");
|
oledWiFiStatus("WIFI PUTUS");
|
||||||
@ -163,6 +209,10 @@ void setup()
|
|||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
delay(500);
|
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 =================
|
// ================= OLED INIT =================
|
||||||
|
|
||||||
Wire.begin(21, 22);
|
Wire.begin(21, 22);
|
||||||
@ -170,9 +220,7 @@ void setup()
|
|||||||
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
|
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR))
|
||||||
{
|
{
|
||||||
Serial.println("OLED tidak ditemukan!");
|
Serial.println("OLED tidak ditemukan!");
|
||||||
|
while (true) delay(1000);
|
||||||
while (true)
|
|
||||||
delay(1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================= WIFI INIT =================
|
// ================= WIFI INIT =================
|
||||||
@ -182,11 +230,8 @@ void setup()
|
|||||||
if (!connectWiFi())
|
if (!connectWiFi())
|
||||||
{
|
{
|
||||||
Serial.println("[ERROR] WiFi gagal!");
|
Serial.println("[ERROR] WiFi gagal!");
|
||||||
|
|
||||||
oledWiFiStatus("RESTART ESP32");
|
oledWiFiStatus("RESTART ESP32");
|
||||||
|
|
||||||
delay(2000);
|
delay(2000);
|
||||||
|
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,14 +260,12 @@ void setup()
|
|||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
MQ135.update();
|
MQ135.update();
|
||||||
|
|
||||||
r0_135 += MQ135.calibrate(RATIO_CLEAN_MQ135);
|
r0_135 += MQ135.calibrate(RATIO_CLEAN_MQ135);
|
||||||
|
updateGPS(); // keep GPS data flowing
|
||||||
delay(600);
|
delay(600);
|
||||||
}
|
}
|
||||||
|
|
||||||
r0_135 /= 10;
|
r0_135 /= 10;
|
||||||
|
|
||||||
MQ135.setR0(r0_135);
|
MQ135.setR0(r0_135);
|
||||||
|
|
||||||
// ================= MQ7 =================
|
// ================= MQ7 =================
|
||||||
@ -235,14 +278,12 @@ void setup()
|
|||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
MQ7.update();
|
MQ7.update();
|
||||||
|
|
||||||
r0_7 += MQ7.calibrate(RATIO_CLEAN_MQ7);
|
r0_7 += MQ7.calibrate(RATIO_CLEAN_MQ7);
|
||||||
|
updateGPS();
|
||||||
delay(600);
|
delay(600);
|
||||||
}
|
}
|
||||||
|
|
||||||
r0_7 /= 10;
|
r0_7 /= 10;
|
||||||
|
|
||||||
MQ7.setR0(r0_7);
|
MQ7.setR0(r0_7);
|
||||||
|
|
||||||
// ================= CHECK CALIBRATION =================
|
// ================= CHECK CALIBRATION =================
|
||||||
@ -250,32 +291,18 @@ void setup()
|
|||||||
if (r0_135 <= 0 || r0_7 <= 0)
|
if (r0_135 <= 0 || r0_7 <= 0)
|
||||||
{
|
{
|
||||||
Serial.println("Kalibrasi gagal!");
|
Serial.println("Kalibrasi gagal!");
|
||||||
|
oledMQStatus("KALIBRASI GAGAL", "", "", "RESTART ESP32...");
|
||||||
oledMQStatus(
|
|
||||||
"KALIBRASI GAGAL",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"RESTART ESP32...");
|
|
||||||
|
|
||||||
delay(2000);
|
delay(2000);
|
||||||
|
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("Kalibrasi selesai!");
|
Serial.println("Kalibrasi selesai!");
|
||||||
|
|
||||||
Serial.print("MQ135 R0 = ");
|
Serial.print("MQ135 R0 = ");
|
||||||
Serial.println(r0_135);
|
Serial.println(r0_135);
|
||||||
|
|
||||||
Serial.print("MQ7 R0 = ");
|
Serial.print("MQ7 R0 = ");
|
||||||
Serial.println(r0_7);
|
Serial.println(r0_7);
|
||||||
|
|
||||||
oledMQStatus(
|
oledMQStatus("KALIBRASI OK", "...", "Mulai Monitoring", "...");
|
||||||
"KALIBRASI OK",
|
|
||||||
"...",
|
|
||||||
"Mulai Monitoring",
|
|
||||||
"...");
|
|
||||||
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,11 +318,8 @@ void loop()
|
|||||||
if (!ensureWiFi())
|
if (!ensureWiFi())
|
||||||
{
|
{
|
||||||
Serial.println("[WiFi] Recover failed!");
|
Serial.println("[WiFi] Recover failed!");
|
||||||
|
|
||||||
oledWiFiStatus("WIFI ERROR");
|
oledWiFiStatus("WIFI ERROR");
|
||||||
|
|
||||||
delay(5000);
|
delay(5000);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,31 +327,20 @@ void loop()
|
|||||||
|
|
||||||
MQ135.setA(110.47);
|
MQ135.setA(110.47);
|
||||||
MQ135.setB(-2.862);
|
MQ135.setB(-2.862);
|
||||||
|
|
||||||
float co2 = readAverage(MQ135);
|
float co2 = readAverage(MQ135);
|
||||||
|
if (co2 < 0) co2 = 0;
|
||||||
if (co2 < 0)
|
|
||||||
co2 = 0;
|
|
||||||
|
|
||||||
// =================================================
|
|
||||||
|
|
||||||
MQ135.setA(605.18);
|
MQ135.setA(605.18);
|
||||||
MQ135.setB(-3.937);
|
MQ135.setB(-3.937);
|
||||||
|
|
||||||
float benzene = readAverage(MQ135);
|
float benzene = readAverage(MQ135);
|
||||||
|
if (benzene < 0) benzene = 0;
|
||||||
if (benzene < 0)
|
|
||||||
benzene = 0;
|
|
||||||
|
|
||||||
// =============== MQ7 ===================
|
// =============== MQ7 ===================
|
||||||
|
|
||||||
MQ7.setA(99.042);
|
MQ7.setA(99.042);
|
||||||
MQ7.setB(-1.518);
|
MQ7.setB(-1.518);
|
||||||
|
|
||||||
float co = readAverage(MQ7);
|
float co = readAverage(MQ7);
|
||||||
|
if (co < 0) co = 0;
|
||||||
if (co < 0)
|
|
||||||
co = 0;
|
|
||||||
|
|
||||||
// ========== AIR QUALITY ESTIMATION =====
|
// ========== AIR QUALITY ESTIMATION =====
|
||||||
|
|
||||||
@ -335,16 +348,12 @@ void loop()
|
|||||||
|
|
||||||
if (co2 > 700)
|
if (co2 > 700)
|
||||||
aq -= map(co2, 700, 2000, 0, 50);
|
aq -= map(co2, 700, 2000, 0, 50);
|
||||||
|
|
||||||
if (co2 > 2000)
|
if (co2 > 2000)
|
||||||
aq -= map(co2, 2000, 5000, 50, 80);
|
aq -= map(co2, 2000, 5000, 50, 80);
|
||||||
|
|
||||||
if (co > 10)
|
if (co > 10)
|
||||||
aq -= map(co, 10, 50, 0, 30);
|
aq -= map(co, 10, 50, 0, 30);
|
||||||
|
|
||||||
if (co > 50)
|
if (co > 50)
|
||||||
aq -= 30;
|
aq -= 30;
|
||||||
|
|
||||||
if (benzene > 5)
|
if (benzene > 5)
|
||||||
aq -= map(benzene, 5, 50, 0, 40);
|
aq -= map(benzene, 5, 50, 0, 40);
|
||||||
|
|
||||||
@ -353,49 +362,71 @@ void loop()
|
|||||||
// ================= STATUS =================
|
// ================= STATUS =================
|
||||||
|
|
||||||
String 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)
|
// =============== GPS READ ==================
|
||||||
status = "Sangat Baik";
|
|
||||||
else if (aq >= 70)
|
String gps_coords = getGPSCoordinates();
|
||||||
status = "Baik";
|
String gps_status = getGPSStatus();
|
||||||
else if (aq >= 50)
|
|
||||||
status = "Sedang";
|
|
||||||
else if (aq >= 30)
|
|
||||||
status = "Buruk";
|
|
||||||
else
|
|
||||||
status = "Sangat Buruk";
|
|
||||||
|
|
||||||
// =============== OLED DISPLAY ==========
|
// =============== OLED DISPLAY ==========
|
||||||
|
// 6 lines fit on 128x64 with textSize(1)
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
|
||||||
oledMQStatus(
|
display.println("CO2:" + String(co2, 1) + " CO:" + String(co, 1));
|
||||||
"CO2 : " + String(co2) + " ppm",
|
display.println("BZ :" + String(benzene, 1) + " AQ:" + String(aq) + "%");
|
||||||
"CO : " + String(co) + " ppm",
|
display.println(status);
|
||||||
"BZ : " + String(benzene) + " ppm",
|
display.println("GPS: " + gps_status);
|
||||||
"AQ : " + String(aq) + " % ",
|
|
||||||
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 =================
|
||||||
|
|
||||||
Serial.println("===== STATUS UDARA =====");
|
Serial.println("===== STATUS UDARA =====");
|
||||||
|
|
||||||
Serial.print("CO2 : ");
|
Serial.print("CO2 : ");
|
||||||
Serial.print(co2);
|
Serial.print(co2);
|
||||||
Serial.println(" ppm");
|
Serial.println(" ppm");
|
||||||
|
|
||||||
Serial.print("CO : ");
|
Serial.print("CO : ");
|
||||||
Serial.print(co);
|
Serial.print(co);
|
||||||
Serial.println(" ppm");
|
Serial.println(" ppm");
|
||||||
|
|
||||||
Serial.print("BZ : ");
|
Serial.print("BZ : ");
|
||||||
Serial.print(benzene);
|
Serial.print(benzene);
|
||||||
Serial.println(" ppm");
|
Serial.println(" ppm");
|
||||||
|
|
||||||
Serial.print("AQ : ");
|
Serial.print("AQ : ");
|
||||||
Serial.print(aq);
|
Serial.print(aq);
|
||||||
Serial.print("% ");
|
Serial.print("% ");
|
||||||
|
|
||||||
Serial.println(status);
|
Serial.println(status);
|
||||||
|
Serial.print("GPS : ");
|
||||||
|
Serial.println(gps_coords);
|
||||||
|
Serial.print("GPS status: ");
|
||||||
|
Serial.println(gps_status);
|
||||||
Serial.println("========================\n");
|
Serial.println("========================\n");
|
||||||
|
|
||||||
delay(5000);
|
delay(5000);
|
||||||
@ -409,12 +440,13 @@ void loop()
|
|||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
|
||||||
String url = String(server) + "/api/update?";
|
String url = String(server) + "/api/update?";
|
||||||
|
|
||||||
url += "co2=" + String(co2);
|
url += "co2=" + String(co2);
|
||||||
url += "&co=" + String(co);
|
url += "&co=" + String(co);
|
||||||
url += "&bz=" + String(benzene);
|
url += "&bz=" + String(benzene);
|
||||||
url += "&aq=" + String(aq);
|
url += "&aq=" + String(aq);
|
||||||
url += "&id=2";
|
url += "&id=2";
|
||||||
|
url += "&lat=" + lat;
|
||||||
|
url += "&lng=" + lng;
|
||||||
|
|
||||||
Serial.print("[HTTP] GET ");
|
Serial.print("[HTTP] GET ");
|
||||||
Serial.println(url);
|
Serial.println(url);
|
||||||
@ -422,7 +454,6 @@ void loop()
|
|||||||
oledWiFiStatus("MENGIRIM DATA...");
|
oledWiFiStatus("MENGIRIM DATA...");
|
||||||
|
|
||||||
http.begin(url);
|
http.begin(url);
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
if (httpCode > 0)
|
if (httpCode > 0)
|
||||||
@ -431,26 +462,21 @@ void loop()
|
|||||||
Serial.println(httpCode);
|
Serial.println(httpCode);
|
||||||
|
|
||||||
String response = http.getString();
|
String response = http.getString();
|
||||||
|
|
||||||
Serial.println("----- HTTP RESPONSE -----");
|
Serial.println("----- HTTP RESPONSE -----");
|
||||||
Serial.println(response);
|
Serial.println(response);
|
||||||
Serial.println("-------------------------");
|
Serial.println("-------------------------");
|
||||||
|
|
||||||
int jsonStart = response.indexOf('{');
|
int jsonStart = response.indexOf('{');
|
||||||
|
|
||||||
if (jsonStart >= 0)
|
if (jsonStart >= 0)
|
||||||
{
|
{
|
||||||
String json = response.substring(jsonStart);
|
String json = response.substring(jsonStart);
|
||||||
|
|
||||||
Serial.print("[JSON] ");
|
Serial.print("[JSON] ");
|
||||||
Serial.println(json);
|
Serial.println(json);
|
||||||
|
|
||||||
oledWiFiStatus("RESP OK");
|
oledWiFiStatus("RESP OK");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial.println("[ERROR] No JSON found!");
|
Serial.println("[ERROR] No JSON found!");
|
||||||
|
|
||||||
oledWiFiStatus("RESP ERROR");
|
oledWiFiStatus("RESP ERROR");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,7 +484,6 @@ void loop()
|
|||||||
{
|
{
|
||||||
Serial.print("[ERROR] HTTP failed: ");
|
Serial.print("[ERROR] HTTP failed: ");
|
||||||
Serial.println(http.errorToString(httpCode));
|
Serial.println(http.errorToString(httpCode));
|
||||||
|
|
||||||
oledWiFiStatus("GAGAL KIRIM");
|
oledWiFiStatus("GAGAL KIRIM");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,7 +492,6 @@ void loop()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial.println("[ERROR] WiFi disconnected!");
|
Serial.println("[ERROR] WiFi disconnected!");
|
||||||
|
|
||||||
oledWiFiStatus("WIFI PUTUS");
|
oledWiFiStatus("WIFI PUTUS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
512
src/main.cpp.again
Normal file
512
src/main.cpp.again
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
// =====================================================
|
||||||
|
// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 + GPS (BN-220)
|
||||||
|
// WiFi Version
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <MQUnifiedsensor.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include <TinyGPSPlus.h>
|
||||||
|
|
||||||
|
// ================== 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);
|
||||||
|
}
|
||||||
477
src/main.cpp.great
Normal file
477
src/main.cpp.great
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
// =====================================================
|
||||||
|
// ESP32 + MQ-135 + MQ-7 + OLED SSD1306 (0.96" 128x64)
|
||||||
|
// WiFi Version
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <MQUnifiedsensor.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
|
||||||
|
// ================== 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);
|
||||||
|
}
|
||||||
104
src/main.cpp.testgps
Normal file
104
src/main.cpp.testgps
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#include <TinyGPSPlus.h>
|
||||||
|
|
||||||
|
// ---- 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user