#define BLYNK_TEMPLATE_ID "TMPL6jHJBZ0U5"
#define BLYNK_TEMPLATE_NAME "tebe"
#define BLYNK_AUTH_TOKEN "gSMn66bhfMe7-XEgGxM6XRbsZ3om8V2y"
#include <WiFi.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <BlynkSimpleEsp32.h>
// ⚠️ GANTI INI 3 HAL!
char auth[] = "gSMn66bhfMe7-XEgGxM6XRbsZ3om8V2y";
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// Pin Definitions
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define RELAY_PIN 5
// Objects
DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2);
BlynkTimer timer;
// Variables
float temperature = 0;
float humidity = 0;
bool relayState = false;
float tempThreshold = 28.0;
float humidThreshold = 60.0;
unsigned long lastUpdate = 0;
const unsigned long updateInterval = 2000;
void setup() {
Serial.begin(115200);
// Initialize Hardware
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
dht.begin();
lcd.init();
lcd.backlight();
// LCD Startup
lcd.setCursor(0, 0);
lcd.print("Sistem Starting...");
lcd.setCursor(0, 1);
lcd.print("Connect WiFi...");
// Blynk Connect
Blynk.begin(auth, ssid, pass);
// Timer untuk Blynk update
timer.setInterval(2000L, blynkUpdate);
Serial.println("=== SISTEM SIAP ===");
lcd.clear();
lcd.print("Blynk OK!");
delay(1000);
}
void loop() {
Blynk.run();
timer.run();
// Update sensor setiap 2 detik
if (millis() - lastUpdate > updateInterval) {
readSensors();
autoControlRelay();
updateDisplay();
printToSerial();
lastUpdate = millis();
}
}
void readSensors() {
temperature = dht.readTemperature();
humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("❌ DHT Read Failed!");
temperature = 0;
humidity = 0;
return;
}
}
// ========================= BLYNK FUNCTIONS =========================
// Update data ke Blynk (3 widget: V0=Switch, V1=Suhu, V2=Kelembaban)
void blynkUpdate() {
Blynk.virtualWrite(V1, temperature); // Suhu ke Value Display V1
Blynk.virtualWrite(V2, humidity); // Kelembaban ke Value Display V2
}
// Blynk Switch V0 - Manual Control Relay
BLYNK_WRITE(V0) {
int value = param.asInt();
relayState = value;
digitalWrite(RELAY_PIN, relayState);
String status = relayState ? "ON (Manual)" : "OFF (Manual)";
Serial.println("🔘 Blynk: " + status);
}
// ========================= AUTO CONTROL =========================
void autoControlRelay() {
bool autoOn = (temperature > tempThreshold) || (humidity > humidThreshold);
if (autoOn && !relayState) {
relayState = true;
digitalWrite(RELAY_PIN, HIGH);
Serial.println("🤖 AUTO: Relay ON (Threshold)");
}
else if (!autoOn && relayState) {
relayState = false;
digitalWrite(RELAY_PIN, LOW);
Serial.println("🤖 AUTO: Relay OFF");
}
}
// ========================= DISPLAY =========================
void updateDisplay() {
lcd.clear();
// Baris 1: Suhu & Kelembaban
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperature, 1);
lcd.print("C H:");
lcd.print(humidity, 1);
lcd.print("%");
// Baris 2: Relay + Threshold
lcd.setCursor(0, 1);
lcd.print("R:");
lcd.print(relayState ? "ON" : "OFF");
lcd.print(" TH:");
lcd.print(tempThreshold, 0);
lcd.print("C");
}
void printToSerial() {
Serial.println("═════ STATUS ═════");
Serial.print("🌡️ Suhu: "); Serial.print(temperature, 1); Serial.println(" °C");
Serial.print("💧 Kelembaban: "); Serial.print(humidity, 1); Serial.println(" %");
Serial.print("🔌 Relay: "); Serial.println(relayState ? "ON" : "OFF");
Serial.print("🎯 Threshold: "); Serial.print(tempThreshold); Serial.print("°C / "); Serial.print(humidThreshold); Serial.println("%");
Serial.println("══════════════════");
}