/*
monitoring-persentase-air_ESP32-v1_3
*/
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define LEBAR_LAYAR 128
#define TINGGI_LAYAR 64
Adafruit_SSD1306 oled(LEBAR_LAYAR, TINGGI_LAYAR, &Wire, -1);
// Pin Definitions
const int TRIG_PIN_B = 26;
const int ECHO_PIN_B = 27;
const int TRIG_PIN_A = 14;
const int ECHO_PIN_A = 12;
const int DATA_PIN = 25;
const int CLOCK_PIN = 32;
const int LATCH_PIN = 33;
const int DHT_PIN = 23;
const int PIN_DO_MQ2 = 22;
const int PIN_BUZZER = 21;
const int PIN_TOMBOL = 19;
// Sensor dan Perangkat Keras
DHT dht(DHT_PIN, DHT22);
const byte LED_PATTERNS[] = {
0b00000000, 0b00000001, 0b00000011, 0b00000111,
0b00001111, 0b00011111, 0b00111111, 0b01111111,
0b11111111, 0b11111110, 0b11111100, 0b11111000,
0b11110000, 0b11100000, 0b11000000, 0b10000000
};
// Konfigurasi Sensor
const float JARAK_KOSONG_B = 79.0, JARAK_PENUH_B = 16.5, RADIUS_TOREN_B = 24.5;
const float JARAK_KOSONG_A = 89.0, JARAK_PENUH_A = 11.0, RADIUS_TOREN_A = 83.0;
int modeTampilan = 0; // 0: suhu, 1: torn bawah, 2: torn atas, 3: semua
bool tombolDitekan = false;
unsigned long waktuTerakhirTekan = 0;
unsigned long waktuIdle = 0;
const unsigned long BATAS_IDLE = 15000;
float suhu = 0.0, kelembaban = 0.0;
float persenA = 0.0, persenB = 0.0;
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN_B, OUTPUT); pinMode(ECHO_PIN_B, INPUT);
pinMode(TRIG_PIN_A, OUTPUT); pinMode(ECHO_PIN_A, INPUT);
pinMode(DATA_PIN, OUTPUT); pinMode(CLOCK_PIN, OUTPUT); pinMode(LATCH_PIN, OUTPUT);
pinMode(PIN_DO_MQ2, INPUT); pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_TOMBOL, INPUT_PULLUP);
dht.begin();
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("failed to start SSD1306 OLED"));
while (1);
}
oled.clearDisplay();
oled.display();
}
float readUltrasonicSensor(int trigPin, int echoPin) {
digitalWrite(trigPin, LOW); delayMicroseconds(2);
digitalWrite(trigPin, HIGH); delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long durasi = pulseIn(echoPin, HIGH, 30000);
if (durasi == 0) return -1;
return (durasi * 0.034) / 2;
}
int calculateVolume(float radius, float height) {
float volume = 3.14159 * pow(radius, 2) * height;
return volume / 1000;
}
void updateShiftRegister(int level) {
if (level < 0) level = 0;
if (level > 15) level = 15;
byte ledPattern = LED_PATTERNS[level];
digitalWrite(LATCH_PIN, LOW);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, ledPattern);
digitalWrite(LATCH_PIN, HIGH);
}
void handleBuzzer(int status) {
if (status == LOW) {
for (int i = 0; i < 10; i++) {
digitalWrite(PIN_BUZZER, HIGH);
delay(100);
digitalWrite(PIN_BUZZER, LOW);
delay(100);
}
} else {
digitalWrite(PIN_BUZZER, LOW);
}
}
void tampilkanOLED() {
oled.clearDisplay();
oled.setTextSize(1);
oled.setTextColor(WHITE);
switch (modeTampilan) {
case 0:
oled.setCursor(0, 0);
oled.println("Suhu & Kelembaban:");
oled.setCursor(0, 20);
oled.setTextSize(1);
oled.print("Suhu: ");
oled.print(suhu, 1);
oled.println(" C");
oled.setCursor(0, 35);
oled.print("Kelembaban: ");
oled.print(kelembaban, 1);
oled.println(" %");
break;
case 1:
oled.setCursor(0, 0);
oled.println("Torn Bawah:");
oled.setTextSize(2);
oled.setCursor(20, 30);
oled.print(persenB, 0);
oled.println(" %");
break;
case 2:
oled.setCursor(0, 0);
oled.println("Torn Atas:");
oled.setTextSize(2);
oled.setCursor(20, 30);
oled.print(persenA, 0);
oled.println(" %");
break;
case 3:
oled.setCursor(0, 0);
oled.println("Semua Data:");
oled.setTextSize(1);
oled.setCursor(0, 12);
oled.print("Suhu : "); oled.print(suhu, 1); oled.println(" C");
oled.setCursor(0, 24);
oled.print("Kelembab.: "); oled.print(kelembaban, 1); oled.println(" %");
oled.setCursor(0, 36);
oled.print("Torn Bwh : "); oled.print(persenB, 0); oled.println(" %");
oled.setCursor(0, 48);
oled.print("Torn Ats : "); oled.print(persenA, 0); oled.println(" %");
break;
}
oled.display();
}
void sendSensorData() {
// Torn Bawah
float jarakB = readUltrasonicSensor(TRIG_PIN_B, ECHO_PIN_B);
float tinggiB = JARAK_KOSONG_B - jarakB;
persenB = map(jarakB, JARAK_PENUH_B, JARAK_KOSONG_B, 100, 0);
int volumeB = calculateVolume(RADIUS_TOREN_B, tinggiB);
// Torn Atas
float jarakA = readUltrasonicSensor(TRIG_PIN_A, ECHO_PIN_A);
float tinggiA = JARAK_KOSONG_A - jarakA;
persenA = map(jarakA, JARAK_PENUH_A, JARAK_KOSONG_A, 100, 0);
int volumeA = calculateVolume(RADIUS_TOREN_A, tinggiA);
// DHT
suhu = dht.readTemperature();
kelembaban = dht.readHumidity();
// Shift register update (berdasarkan torn bawah)
int ledLevel = map(persenB, 0, 200, 0, 16);
updateShiftRegister(ledLevel);
// Serial Debug
Serial.print("Suhu: "); Serial.print(suhu); Serial.print(" C, ");
Serial.print("Kelembaban: "); Serial.print(kelembaban); Serial.println(" %");
Serial.print("Torn Bawah: "); Serial.print(persenB); Serial.println(" %");
Serial.print("Torn Atas : "); Serial.print(persenA); Serial.println(" %");
}
void loop() {
sendSensorData();
// Buzzer (jika ENABLE_MQ2_SENSOR diaktifkan)
#if ENABLE_MQ2_SENSOR
int mq2 = digitalRead(PIN_DO_MQ2);
handleBuzzer(mq2);
#endif
// Cek tombol
if (digitalRead(PIN_TOMBOL) == LOW) {
if (!tombolDitekan) {
modeTampilan = (modeTampilan + 1) % 4; // 0→1→2→3→0
tombolDitekan = true;
waktuTerakhirTekan = millis();
waktuIdle = millis(); // reset idle
}
} else {
tombolDitekan = false;
}
// Kembali ke default (mode 0) setelah idle
if (millis() - waktuIdle > BATAS_IDLE && modeTampilan != 0) {
modeTampilan = 0;
waktuIdle = millis();
}
tampilkanOLED();
delay(1000);
}