TKK_E32221413_Pendeteksi_ke.../main.ino

338 lines
11 KiB
C++

#include "thingProperties.h"
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
// --- DEFINISI PIN ---
#define PIN_DHT 4
#define TIPE_DHT DHT11
#define PIN_MQ3 34
#define PIN_MQ135 35
#define PIN_BUZZER 15
#define PIN_TOMBOL1 13 // Tombol List Buah
#define PIN_TOMBOL2 12 // Tombol Pindah Bawah
#define PIN_TOMBOL3 14 // Tombol Pilih/Enter
// --- KONFIGURASI LCD ---
#define ALAMAT_LCD 0x27
#define KOLOM_LCD 20
#define BARIS_LCD 4
// Inisialisasi komponen
DHT dht(PIN_DHT, TIPE_DHT);
LiquidCrystal_I2C lcd(ALAMAT_LCD, KOLOM_LCD, BARIS_LCD);
struct DataSensor {
float suhu;
float kelembaban;
int nilaiAnalogMQ3;
int nilaiAnalogMQ135;
float nilaiPpmMQ3;
float nilaiPpmMQ135;
String tingkatKematangan;
String namaBuahTerpilih;
};
// --- VARIABEL GLOBAL ---
String daftarBuah[] = {"Apel", "Pepaya", "Pisang", "Alpukat"};
int buahTerpilihLokal = 0;
bool statusBuahDipilih = false;
bool statusTampilDaftarBuah = false;
unsigned long waktuTerakhirSensorDibaca = 0;
unsigned long waktuTerakhirTombolDibaca = 0;
unsigned long waktuTerakhirCloudUpdate = 0;
const unsigned long INTERVAL_SENSOR = 2000; // 2 detik
const unsigned long INTERVAL_CLOUD = 5000; // 5 detik untuk update cloud
const unsigned long JEDA_ANTIBOUNCE = 200; // 200 milidetik
// Status tombol
bool kondisiTombol1 = HIGH, kondisiTombol2 = HIGH, kondisiTombol3 = HIGH;
bool kondisiTerakhirTombol1 = HIGH, kondisiTerakhirTombol2 = HIGH, kondisiTerakhirTombol3 = HIGH;
// Variabel untuk menyimpan tingkat kematangan sebelumnya
String tingkatKematanganSebelumnya = "";
// ==============================================================================
// KONSTANTA KALIBRASI SENSOR MQ
// ==============================================================================
const float TEGANGAN_VCC = 5.0; // Tegangan suplai modul sensor MQ (V)
const float RESISTANSI_BEBAN = 10.0; // Resistansi beban (kOhm)
const int RESOLUSI_ADC = 4095; // Resolusi ADC ESP32
// MQ3 (Alkohol/Etanol) - Ganti dengan nilai kalibrasi Anda!
const float MQ3_R0 = 60.0;
const float MQ3_SLOPE = -0.685;
const float MQ3_INTERCEPT = 1.258;
// MQ135 (Kualitas Udara) - Ganti dengan nilai kalibrasi Anda!
const float MQ135_R0 = 35.7;
const float MQ135_SLOPE = -0.395;
const float MQ135_INTERCEPT = 1.488;
// ==============================================================================
// Struktur untuk ambang batas kematangan buah (dalam PPM)
struct AmbangBatasBuah {
float mentahMQ3Maks;
float matangMQ3Min;
float matangMQ3Maks;
float busukMQ3Min;
float mentahMQ135Maks;
float matangMQ135Min;
float matangMQ135Maks;
float busukMQ135Min;
};
// Definisi ambang batas untuk setiap buah (sesuaikan berdasarkan kalibrasi)
AmbangBatasBuah daftarAmbangBatas[] = {
{29.1, 29.5, 77.0, 78.0, 11.2, 11.7, 17.5, 18.0}, // Apel
{30.0, 30.5, 90.0, 91.0, 13.0, 13.5, 24.0, 24.5}, // Pepaya
{32.0, 32.5, 102.0, 103.0, 12.0, 12.5, 19.0, 19.5}, // Pisang
{29.2, 29.7, 59.0, 60.5, 13.2, 13.7, 21.0, 21.5} // Alpukat
};
void setup() {
Serial.begin(9600);
delay(1500);
// Initialize Arduino IoT Cloud
initProperties();
ArduinoCloud.begin(ArduinoIoTPreferredConnection);
setDebugMessageLevel(2);
ArduinoCloud.printDebugInfo();
dht.begin();
lcd.init();
lcd.backlight();
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_TOMBOL1, INPUT_PULLUP);
pinMode(PIN_TOMBOL2, INPUT_PULLUP);
pinMode(PIN_TOMBOL3, INPUT_PULLUP);
tampilkanPesanSelamatDatang();
Serial.println("=== SISTEM DETEKSI KEMATANGAN BUAH ===");
Serial.println("Sistem siap digunakan!");
delay(5000);
tampilkanMenuUtama();
}
// Fungsi untuk menghitung resistansi sensor Rs
float hitungResistansiSensor(int nilaiAnalog, float teganganVcc, float resistansiBeban, int resolusiAdc) {
float teganganKeluar = nilaiAnalog * (teganganVcc / resolusiAdc);
if (teganganKeluar == 0) return resistansiBeban * 1000;
float resistansiSensor = (teganganVcc / teganganKeluar - 1) * resistansiBeban;
return resistansiSensor; // dalam kOhm
}
// Fungsi untuk mengkonversi Rs/R0 ke PPM
float konversiKePPM(float rasioRsR0, float slope, float intercept) {
if (rasioRsR0 <= 0) return 0.0;
float logRsR0 = log10(rasioRsR0);
return pow(10, (slope * logRsR0) + intercept);
}
void loop() {
ArduinoCloud.update();
unsigned long waktuSekarang = millis();
if (waktuSekarang - waktuTerakhirTombolDibaca >= JEDA_ANTIBOUNCE) {
kelolaTombol();
waktuTerakhirTombolDibaca = waktuSekarang;
}
if (statusBuahDipilih && (waktuSekarang - waktuTerakhirSensorDibaca >= INTERVAL_SENSOR)) {
perbaruiSensor();
waktuTerakhirSensorDibaca = waktuSekarang;
}
// Update Arduino Cloud setiap 5 detik
if (statusBuahDipilih && (waktuSekarang - waktuTerakhirCloudUpdate >= INTERVAL_CLOUD)) {
updateCloudVariables();
waktuTerakhirCloudUpdate = waktuSekarang;
}
}
void updateCloudVariables() {
DataSensor data = bacaSemuaSensor();
// Update cloud variables sesuai dengan yang ada di Arduino Cloud
mq135_ppm = data.nilaiPpmMQ135;
mq3_ppm = data.nilaiPpmMQ3;
namaBuah = daftarBuah[buahTerpilihLokal]; // Mengirim nama buah dari array
suhu = data.suhu;
tingkatKematangan = data.tingkatKematangan;
Serial.println("=== DATA DIKIRIM KE ARDUINO CLOUD ===");
Serial.println("MQ135 PPM: " + String(mq135_ppm, 4));
Serial.println("MQ3 PPM: " + String(mq3_ppm, 4));
Serial.println("Nama Buah Index: " + String(namaBuah));
Serial.println("Suhu: " + String(suhu, 1) + " °C");
Serial.println("Tingkat Kematangan: " + tingkatKematangan);
Serial.println("=====================================");
}
void tampilkanPesanSelamatDatang() {
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" SISTEM PENDETEKSI ");
lcd.setCursor(0, 1); lcd.print(" KEMATANGAN BUAH ");
lcd.setCursor(0, 2); lcd.print(" BERBASIS SENSOR ");
lcd.setCursor(0, 3); lcd.print(" E-NOSE CLOUD ");
}
void tampilkanMenuUtama() {
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" MENU UTAMA ");
lcd.setCursor(0, 1); lcd.print(" Pilih buah untuk ");
lcd.setCursor(0, 2); lcd.print(" mulai deteksi ");
lcd.setCursor(0, 3); lcd.print("=> tekan tombol list");
}
void tampilkanDaftarBuah() {
lcd.clear();
for (int i = 0; i < 4; i++) {
lcd.setCursor(0, i);
if (i == buahTerpilihLokal) {
lcd.print("> " + daftarBuah[i]);
} else {
lcd.print(" " + daftarBuah[i]);
}
}
}
void tampilkanHasilBacaSensor() {
DataSensor data = bacaSemuaSensor();
lcd.clear();
lcd.setCursor(0, 0); lcd.print(daftarBuah[buahTerpilihLokal] + ": " + data.tingkatKematangan);
lcd.setCursor(0, 1); lcd.print("MQ3:" + String(data.nilaiPpmMQ3, 2) + "ppm");
lcd.setCursor(0, 2); lcd.print("MQ135:" + String(data.nilaiPpmMQ135, 2) + "ppm");
lcd.setCursor(0, 3); lcd.print("T:" + String(data.suhu, 1) + "C H:" + String(data.kelembaban, 1) + "%");
// Cek jika tingkat kematangan berubah
if (data.tingkatKematangan != tingkatKematanganSebelumnya) {
// Jika status kematangan berubah, bunyikan buzzer
if (data.tingkatKematangan == "Busuk") {
bunyikanBuzzer(1, 100); // Bunyikan buzzer untuk status "Busuk"
} else if (data.tingkatKematangan == "Matang") {
bunyikanBuzzer(1, 200); // Bunyikan buzzer untuk status "Matang"
}
// Update tingkat kematangan sebelumnya
tingkatKematanganSebelumnya = data.tingkatKematangan;
}
// Tampilkan data di Serial Monitor
Serial.println("=== DATA SENSOR LOKAL ===");
Serial.println("Buah: " + data.namaBuahTerpilih);
Serial.println("Tingkat Kematangan: " + data.tingkatKematangan);
Serial.println("Suhu: " + String(data.suhu, 1) + " °C");
Serial.println("Kelembaban: " + String(data.kelembaban, 1) + " %");
Serial.println("MQ3: " + String(data.nilaiPpmMQ3, 4) + " ppm");
Serial.println("MQ135: " + String(data.nilaiPpmMQ135, 4) + " ppm");
Serial.println("========================");
}
DataSensor bacaSemuaSensor() {
DataSensor data;
data.suhu = dht.readTemperature();
data.kelembaban = dht.readHumidity();
if (isnan(data.suhu) || isnan(data.kelembaban)) {
Serial.println("Error: Gagal membaca sensor DHT11!");
data.suhu = 0.0;
data.kelembaban = 0.0;
}
data.nilaiAnalogMQ3 = analogRead(PIN_MQ3);
data.nilaiAnalogMQ135 = analogRead(PIN_MQ135);
float Rs_MQ3 = hitungResistansiSensor(data.nilaiAnalogMQ3, TEGANGAN_VCC, RESISTANSI_BEBAN, RESOLUSI_ADC);
float rasioRsR0_MQ3 = Rs_MQ3 / MQ3_R0;
data.nilaiPpmMQ3 = konversiKePPM(rasioRsR0_MQ3, MQ3_SLOPE, MQ3_INTERCEPT);
float Rs_MQ135 = hitungResistansiSensor(data.nilaiAnalogMQ135, TEGANGAN_VCC, RESISTANSI_BEBAN, RESOLUSI_ADC);
float rasioRsR0_MQ135 = Rs_MQ135 / MQ135_R0;
data.nilaiPpmMQ135 = konversiKePPM(rasioRsR0_MQ135, MQ135_SLOPE, MQ135_INTERCEPT);
data.tingkatKematangan = tentukanKematangan(data.nilaiPpmMQ3, data.nilaiPpmMQ135, buahTerpilihLokal);
data.namaBuahTerpilih = daftarBuah[buahTerpilihLokal];
return data;
}
String tentukanKematangan(float nilaiPpmMQ3, float nilaiPpmMQ135, int indeksBuah) {
AmbangBatasBuah ambangBatas = daftarAmbangBatas[indeksBuah];
if (nilaiPpmMQ3 >= ambangBatas.busukMQ3Min || nilaiPpmMQ135 >= ambangBatas.busukMQ135Min) {
return "Busuk";
} else if ((nilaiPpmMQ3 >= ambangBatas.matangMQ3Min && nilaiPpmMQ3 <= ambangBatas.matangMQ3Maks) ||
(nilaiPpmMQ135 >= ambangBatas.matangMQ135Min && nilaiPpmMQ135 <= ambangBatas.matangMQ135Maks)) {
return "Matang";
} else {
return "Mentah";
}
}
void kelolaTombol() {
bool tekanTombol1 = digitalRead(PIN_TOMBOL1);
bool tekanTombol2 = digitalRead(PIN_TOMBOL2);
bool tekanTombol3 = digitalRead(PIN_TOMBOL3);
// Tombol 1 - Tampilkan daftar buah atau kembali ke menu
if (tekanTombol1 == LOW && kondisiTerakhirTombol1 == HIGH) {
if (statusBuahDipilih) {
statusBuahDipilih = false;
statusTampilDaftarBuah = false;
buahTerpilihLokal = 0;
tampilkanMenuUtama();
} else {
statusTampilDaftarBuah = true;
buahTerpilihLokal = 0;
tampilkanDaftarBuah();
}
}
// Tombol 2 - Navigasi ke bawah
if (tekanTombol2 == LOW && kondisiTerakhirTombol2 == HIGH && statusTampilDaftarBuah && !statusBuahDipilih) {
buahTerpilihLokal = (buahTerpilihLokal + 1) % 4;
tampilkanDaftarBuah();
}
// Tombol 3 - Pilih buah
if (tekanTombol3 == LOW && kondisiTerakhirTombol3 == HIGH && statusTampilDaftarBuah && !statusBuahDipilih) {
statusBuahDipilih = true;
statusTampilDaftarBuah = false;
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Buah dipilih:");
lcd.setCursor(0, 1); lcd.print(daftarBuah[buahTerpilihLokal]);
lcd.setCursor(0, 2); lcd.print("Letakkan buah...");
lcd.setCursor(0, 3); lcd.print("Membaca sensor...");
delay(2000);
waktuTerakhirSensorDibaca = millis() - INTERVAL_SENSOR;
}
kondisiTerakhirTombol1 = tekanTombol1;
kondisiTerakhirTombol2 = tekanTombol2;
kondisiTerakhirTombol3 = tekanTombol3;
}
void perbaruiSensor() {
if (statusBuahDipilih) {
tampilkanHasilBacaSensor();
}
}
void bunyikanBuzzer(int jumlahBip, int durasi) {
for (int i = 0; i < jumlahBip; i++) {
digitalWrite(PIN_BUZZER, HIGH);
delay(durasi);
digitalWrite(PIN_BUZZER, LOW);
if (i < jumlahBip - 1) {
delay(200);
}
}
}