/* ================= KONFIGURASI BLYNK & FIRMWARE ================= */
#define BLYNK_TEMPLATE_ID "TMPL6XNiUeSEi"
#define BLYNK_TEMPLATE_NAME "Jemuran Otomatis"
#define BLYNK_AUTH_TOKEN "OJGR8tDh4xfnAl2MwYmSXtaA5mzDXrUs"
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <ESP32Servo.h>
/* ================= PIN ================= */
#define LDR_PIN 34
#define RAIN_PIN 35
#define DHT_PIN 15
#define SERVO_PIN 13
#define BUZZER_PIN 25
#define DHTTYPE DHT22
/* ================= OBJEK ================= */
Servo jemuran;
DHT dht(DHT_PIN, DHTTYPE);
BlynkTimer timer;
/* ================= WIFI ================= */
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
/* ================= STATE ================= */
bool jemuranDiLuar = true;
/* ================= KALIBRASI ================= */
const int batasHujan = 2000;
const int batasGelap = 1500;
/* ================= POSISI SERVO ================= */
const int POSISI_KELUAR = 15;
const int POSISI_MASUK = 160;
/* ================= LATCH / DELAY AMAN ================= */
// jemuran baru boleh keluar kalau kondisi aman stabil
unsigned long lastBahayaTime = 0;
const unsigned long AMAN_DELAY = 3000; // 10 detik aman stabil
/* ================= SETUP ================= */
void setup() {
Serial.begin(115200);
/* ===== SERVO ===== */
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
jemuran.setPeriodHertz(50);
jemuran.attach(SERVO_PIN, 500, 2400);
/* ===== SENSOR ===== */
dht.begin();
pinMode(LDR_PIN, INPUT);
pinMode(RAIN_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
/* ===== PRE-CHECK ===== */
int cekHujan = analogRead(RAIN_PIN);
int cekCahaya = analogRead(LDR_PIN);
if (cekHujan < batasHujan || cekCahaya < batasGelap) {
jemuran.write(POSISI_MASUK);
jemuranDiLuar = false;
lastBahayaTime = millis();
Serial.println("BOOT: BAHAYA → DALAM");
} else {
jemuran.write(POSISI_KELUAR);
jemuranDiLuar = true;
Serial.println("BOOT: AMAN → LUAR");
}
/* ===== BLYNK ===== */
Serial.println("Menghubungkan ke Blynk...");
Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);
timer.setInterval(1000L, logikaUtama);
}
/* ================= LOOP ================= */
void loop() {
Blynk.run();
timer.run();
}
/* ================= LOGIKA UTAMA ================= */
void logikaUtama() {
int nilaiHujan = analogRead(RAIN_PIN);
int nilaiLDR = analogRead(LDR_PIN);
bool isHujan = nilaiHujan < batasHujan;
bool isGelap = nilaiLDR < batasGelap;
bool kondisiBahaya = isHujan || isGelap;
/* ===== SIMPAN WAKTU TERAKHIR BAHAYA ===== */
if (kondisiBahaya) {
lastBahayaTime = millis();
}
/* ===== KASUS A: BAHAYA → MASUK ===== */
if (kondisiBahaya && jemuranDiLuar) {
Serial.println("STATUS: BAHAYA! Jemuran MASUK");
jemuran.write(POSISI_MASUK);
jemuranDiLuar = false;
Blynk.virtualWrite(V0, "BAHAYA! Jemuran Masuk");
Blynk.virtualWrite(V1, 1);
}
/* ===== KASUS B: AMAN STABIL → KELUAR ===== */
else if (
!kondisiBahaya &&
!jemuranDiLuar &&
(millis() - lastBahayaTime >= AMAN_DELAY)
) {
Serial.println("STATUS: AMAN STABIL! Jemuran KELUAR");
jemuran.write(POSISI_KELUAR);
jemuranDiLuar = true;
Blynk.virtualWrite(V0, "AMAN. Jemuran Keluar");
Blynk.virtualWrite(V1, 0);
}
/* ===== BUZZER (TANPA TONE / TANPA PWM) ===== */
digitalWrite(BUZZER_PIN, isHujan ? HIGH : LOW);
/* ===== MONITOR ===== */
Serial.print("Hujan: "); Serial.print(nilaiHujan);
Serial.print(" | Cahaya: "); Serial.print(nilaiLDR);
Serial.print(" | Bahaya: "); Serial.print(kondisiBahaya);
Serial.print(" | TimerAman(ms): ");
Serial.print(millis() - lastBahayaTime);
Serial.print(" | Posisi: ");
Serial.println(jemuranDiLuar ? "LUAR" : "DALAM");
}