Halo Inovator Muda! 🌟

Pernahkah kamu dimarahi ibu karena lupa mengangkat jemuran saat hujan turun? Hari ini, kita akan menyelesaikan masalah itu selamanya dengan teknologi Internet of Things (IoT)!

Kemampuan Robot Jemuran Kita:

💧

Mendeteksi rintik hujan sekecil apapun.

⚙️

Menarik jemuran secara otomatis menggunakan motor.

🔊

Membunyikan alarm peringatan (Buzzer).

📱

Mengirim pesan WhatsApp langsung ke HP-mu!

Misi 1: Pasukan Perangkat Keras

Sebelum memprogram, kita harus merakit komponennya. Pastikan Wemos TIDAK terhubung ke komputer/listrik saat merakit!

🧠

Wemos D1 Mini

Otak sistem dengan fitur WiFi.

🌧️

Sensor Hujan

Mata untuk melihat tetesan air.

🦾

Servo SG90

Otot penarik tali jemuran.

Panduan Merakit (Wiring)

Komponen Pin di Komponen Pin di Wemos D1 Mini Fungsi
Sensor Hujan VCC 3.3V / 5V Tenaga listrik
GND GND Ground / Negatif
D0 D5 Sinyal digital hujan
Motor Servo Merah (VCC) 5V Tenaga motor
Coklat (GND) GND Ground
Kuning/Oranye D6 Sinyal penggerak
Buzzer Kaki Panjang (+) D7 Sinyal alarm
Kaki Pendek (-) GND Ground
LCD I2C VCC 5V Tenaga layar
GND GND Ground
SDA D2 Jalur Data
SCL D1 Jalur Waktu (Clock)

Simulator Pin Wemos D1 Mini

Arahkan kursor (hover) ke pin yang berwarna untuk melihat jalur kabelnya.

ANTENNA
RST
A0
D0
D5
D6
D7
D8
3V3
TX
RX
D1
D2
D3
D4
GND
5V
ESP8266

Misi 2: Persiapan Markas (Software)

1. Menginstal Library di Arduino IDE

Buka aplikasi Arduino IDE di komputermu. Kita butuh memanggil beberapa "buku pintar" (Library) agar otak Wemos bisa bekerja mengendalikan WiFi dan Layar.

Tugas:

Pastikan kamu sudah menginstal library berikut melalui menu Sketch > Include Library > Manage Libraries:

🌐

Blynk

Oleh: Volodymyr Shymanskyy. (Untuk koneksi IoT).

📺

LiquidCrystal I2C

Oleh: Frank de Brabander. (Untuk menampilkan teks di layar).

2. Pengaturan Aplikasi / Web Blynk

Agar alat bisa mengirim status cuaca (tulisan "HUJAN" atau "CERAH") ke HP/Komputer, ikuti langkah wajib ini di website Blynk Console:

  1. Buka Blynk Console (web) dan buat Template baru.
  2. Masuk ke tab Datastreams, klik tombol New Datastream lalu pilih Virtual Pin.
  3. Isi pengaturan Datastream persis seperti ini:
    • Name: Status Cuaca
    • Pin: V1
    • Data Type: String 👈 (Ini sangat penting!)
  4. Buka tab Web Dashboard, seret (drag) Widget bernama Value Display atau Label ke layar.
  5. Klik tombol Pengaturan (ikon Gear ⚙️) pada widget tersebut, lalu pada bagian Datastream, pilih V1 (Status Cuaca). Simpan pengaturan.
💡

Kenapa Data Type harus "String"? Karena kode alat kita mengirimkan sebuah teks panjang (seperti "HUJAN! Jemuran diamankan."). Jika kamu salah memilih tipe data (misalnya memilih tipe 'Integer' atau angka), teks tersebut tidak akan muncul di layar Blynk kamu!

Misi 3: Memahami Logika Cerdas

Kita tidak akan langsung melihat kode utuh. Mari pahami 3 konsep rahasia di balik program jemuran pintar kita.

1. Konsep "Debounce" (Anti-Galau)

Sensor hujan kadang bisa "galau". Tetesan embun kecil bisa membuatnya mengira sedang hujan lebat. Solusinya adalah hitungan mundur (Debounce). Sistem baru bertindak setelah kondisi stabil beberapa detik.

Simulasi Debounce Sensor

Grafik menunjukkan bagaimana sinyal sensor yang berantakan (biru) diubah menjadi keputusan sistem yang stabil (merah).

2. Gerakan Halus (Slow Servo)

Jika jemuran ditarik terlalu cepat, pakaian bisa terlempar! Kita membuat fungsi moveServoSlow(). Motor diputar derajat demi derajat dengan jeda 15 milidetik agar halus seperti ditarik manusia.

3. Notifikasi Anti-Spam

Bayangkan jika robotmu mengirim pesan WA setiap 1 detik saat hujan. HP-mu pasti hang! Robot hanya mengirim pesan WA tepat 1 kali saat status berubah (Cerah ➔ Hujan, atau sebaliknya).

Misi 4: Unggah Program!

Dapatkan kode lengkap dari Gurumu di bawah ini. Sebelum menekan tombol Upload, kamu WAJIB mengubah baris konfigurasi WiFi dan Nomor WA sesuai dengan kondisimu.

Kode Program Lengkap

Jemuran_Otomatis.ino
/*
 * Proyek: IoT Pendeteksi Hujan & Pengaman Jemuran Otomatis
 * Board : Wemos D1 Mini (ESP8266)
 */

// Konfigurasi Blynk (Harus diletakkan paling atas)
#define BLYNK_TEMPLATE_ID "TMPL6zGCVNiNo" // Ganti dengan Template ID Blynk
#define BLYNK_TEMPLATE_NAME "MONITORINGHUJAN" // Ganti dengan Template Name BLynk
#define BLYNK_AUTH_TOKEN "vi0OTtXX9CaNS6Hq5UvcO-2Bd4k8OXrd"; // Ganti dengan TOKEN BLYNK

// --- Include Library ---
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>

// --- Konfigurasi WiFi ---
char ssid[] = "XXXXXXXXXXXX";       // Ganti dengan nama WiFi Anda
char pass[] = "XXXXXXXXXXXX";   // Ganti dengan password WiFi Anda

// --- Konfigurasi Fonnte API ---
String fonnteToken = "xxxxxxxxxxxx"; // Ganti dengan Token API WA
String targetWA = "08xxxxxxxxxxxx"; // Ganti dengan Nomor WA tujuan (awali 08)

// --- Definisi Pin Wemos D1 Mini ---
#define RAIN_SENSOR_PIN D5  // Pin Digital Sensor Hujan
#define SERVO_PIN D6        // Pin PWM Servo SG90
#define BUZZER_PIN D7       // Pin Buzzer

// --- Inisialisasi Objek ---
Servo myServo;
LiquidCrystal_I2C lcd(0x27, 16, 2); 
BlynkTimer timer;

// --- Variabel State ---
bool isRaining = false; 

// Variabel Timer Buzzer (menggunakan millis)
unsigned long buzzerStartTime = 0;
bool isBuzzerOn = false;

// Variabel Debounce
int dryCount = 0;
int wetCount = 0;
const int DRY_THRESHOLD = 5; // 5x pembacaan = 10 detik
const int WET_THRESHOLD = 2; // 2x pembacaan = 4 detik

// --- Fungsi Menggerakkan Servo Perlahan ---
void moveServoSlow(int targetAngle) {
  int currentAngle = myServo.read();
  if (currentAngle < targetAngle) {
    for (int pos = currentAngle; pos <= targetAngle; pos += 1) {
      myServo.write(pos);
      delay(15); 
    }
  } else {
    for (int pos = currentAngle; pos >= targetAngle; pos -= 1) {
      myServo.write(pos);
      delay(15);
    }
  }
}

void setup() {
  Serial.begin(115200);
  
  pinMode(RAIN_SENSOR_PIN, INPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW); 
  
  myServo.attach(SERVO_PIN);
  myServo.write(0); 

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Sistem Jemuran");
  lcd.setCursor(0, 1);
  lcd.print("Menghubungkan...");

  Blynk.begin(BLYNK_AUTH_TOKEN, ssid, pass);

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("WiFi Connected!");
  delay(2000);
  
  timer.setInterval(2000L, checkRainStatus);
  
  updateDisplay("Sistem Aktif", "Cerah - Aman");
  Blynk.virtualWrite(V1, "Sistem Aktif - Cuaca Cerah"); 
}

void loop() {
  Blynk.run();
  timer.run();

  // Mengecek apakah buzzer sudah menyala selama 5 detik (5000 ms)
  if (isBuzzerOn && (millis() - buzzerStartTime >= 5000)) {
    digitalWrite(BUZZER_PIN, LOW); // Matikan buzzer
    isBuzzerOn = false;            // Reset status buzzer
    Serial.println("Buzzer dimatikan otomatis setelah 5 detik.");
  }
}

// --- Fungsi Mengecek Status Hujan ---
void checkRainStatus() {
  int sensorValue = digitalRead(RAIN_SENSOR_PIN); 

  if (sensorValue == LOW) { 
    wetCount++;
    dryCount = 0;
  } else { 
    dryCount++;
    wetCount = 0;
  }

  Serial.print("[DEBUG] Sensor: ");
  Serial.print(sensorValue == LOW ? "BASAH (0)" : "KERING (1)");
  Serial.print(" | Wet: "); Serial.print(wetCount); Serial.print("/"); Serial.print(WET_THRESHOLD);
  Serial.print(" | Dry: "); Serial.print(dryCount); Serial.print("/"); Serial.print(DRY_THRESHOLD);
  Serial.print(" | Status: "); Serial.println(isRaining ? "HUJAN" : "CERAH");

  bool newRainStatus = isRaining;

  if (wetCount >= WET_THRESHOLD && !isRaining) {
    newRainStatus = true;
  } else if (dryCount >= DRY_THRESHOLD && isRaining) {
    newRainStatus = false;
  }

  if (newRainStatus != isRaining) {
    isRaining = newRainStatus; 

    if (isRaining) {
      Serial.println("Hujan Terdeteksi!");
      updateDisplay("Status: HUJAN!", "Jemuran Ditarik");
      Blynk.virtualWrite(V1, "HUJAN! Jemuran diamankan."); 
      
      digitalWrite(BUZZER_PIN, HIGH); 
      buzzerStartTime = millis(); // Catat waktu mulai bunyi
      isBuzzerOn = true;          // Tandai buzzer sedang bunyi
      
      moveServoSlow(180); 
      sendWhatsApp("Peringatan! Hujan turun, jemuran telah ditarik otomatis.");
      
    } else {
      Serial.println("Hujan Reda.");
      digitalWrite(BUZZER_PIN, LOW); 
      isBuzzerOn = false; // Pastikan status buzzer direset
      
      updateDisplay("Status: CERAH", "Jemuran Keluar");
      Blynk.virtualWrite(V1, "CERAH. Jemuran dikeluarkan."); 
      
      moveServoSlow(0); 
      sendWhatsApp("Info Cuaca: Hujan telah reda, jemuran dijemur kembali.");
    }
  }
}

// --- Fungsi Update LCD ---
void updateDisplay(String baris1, String baris2) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(baris1);
  lcd.setCursor(0, 1);
  lcd.print(baris2);
}

// --- Fungsi Kirim Pesan WA ---
void sendWhatsApp(String message) {
  if (WiFi.status() == WL_CONNECTED) {
    WiFiClientSecure client;
    client.setInsecure(); 
    HTTPClient http;
    
    http.begin(client, "https://api.fonnte.com/send");
    http.addHeader("Authorization", fonnteToken);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");

    String postData = "target=" + targetWA + "&message=" + message;

    Serial.println("Mengirim WA...");
    int httpResponseCode = http.POST(postData);

    if (httpResponseCode > 0) {
      Serial.print("WA Terkirim. Code: ");
      Serial.println(httpResponseCode);
    } else {
      Serial.print("Error WA: ");
      Serial.println(httpResponseCode);
    }
    http.end();
  }
}

Langkah Terakhir

Colokkan kabel USB ke Wemos dan klik tombol Upload (➔) di Arduino IDE. Buka Serial Monitor (115200 baud) untuk melihat aktivitas alat.

Misi 5: Uji Coba & Eksperimen

Sekarang saatnya bermain! Siapkan sedikit air. Uji coba sistemmu dan selesaikan tantangan di bawah ini.

Cara Menguji:

  1. Teteskan air ke papan sensor. Lihat apa yang terjadi pada Servo, LCD, dan periksa HP-mu!
  2. Lap papan sensor sampai kering. Tunggu 10 detik, dan lihat jemuranmu kembali keluar.

🏆 Tantangan Untuk Siswa

Apakah kamu bisa memodifikasi kode untuk mengubah cara kerjanya? Centang kotak di bawah ini jika kamu berhasil menyelesaikannya!

"Jangan takut salah mencoba mengubah kode, karena dari kesalahanlah kita belajar menjadi programmer hebat."