#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
// ---------------- CONFIG ----------------
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Ganti TOKEN_BLYNK dengan token kamu (pastikan tidak ada karakter tambahan)
const char* TOKEN_BLYNK = "-f1BDKS6loEVYOm_Qfah3MHnLj1QttTN";
const char* BLYNK_HOST = "http://sgp1.blynk.cloud"; // pakai http untuk stabil di simulator
// Pin & sensor
#define DHTPIN 15 // DATA pin DHT22
#define DHTTYPE DHT22
#define LED_PIN 2 // LED indikator (GPIO2 aman untuk boot)
DHT dht(DHTPIN, DHTTYPE);
// Batas otomatis untuk alarm
const float BATAS_SUHU = 30.0;
// Interval (ms)
const unsigned long INTERVAL_SEND = 10000UL; // kirim data tiap 10 detik
const unsigned long INTERVAL_GET = 5000UL; // baca kontrol V2 tiap 5 detik
// Status
int manualV2 = 0; // 0 = OFF, 1 = ON (dari Blynk)
int ledState = 0; // 0 = OFF, 1 = ON
unsigned long lastSend = 0;
unsigned long lastGet = 0;
void setup() {
Serial.begin(115200);
delay(100);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
dht.begin();
Serial.println();
Serial.print("Menghubungkan ke WiFi...");
WiFi.begin(ssid, password);
unsigned long start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < 10000UL) {
Serial.print(".");
delay(500);
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✅ WiFi terhubung!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("\n❌ Gagal terhubung WiFi (pastikan SSID/Password benar atau Wokwi aktif).");
// tetap lanjut — REST requests akan cek koneksi tiap kali
}
lastSend = millis();
lastGet = millis();
}
String makeUrlSend(float suhu, float hum) {
// gunakan batch update untuk V0 (suhu) dan V1 (kelembapan)
String url = String(BLYNK_HOST) + "/external/api/batch/update?token=" + String(TOKEN_BLYNK);
url += "&V0=" + String(suhu, 2) + "&V1=" + String(hum, 2);
return url;
}
String makeUrlGetV2() {
// baca pin V2 (kontrol LED manual)
String url = String(BLYNK_HOST) + "/external/api/get?token=" + String(TOKEN_BLYNK) + "&pin=V2";
return url;
}
bool sendSensorToBlynk(float suhu, float hum) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ Tidak terkoneksi WiFi saat akan kirim data.");
return false;
}
HTTPClient http;
String url = makeUrlSend(suhu, hum);
Serial.print("Request SEND -> ");
Serial.println(url);
http.begin(url);
int code = http.GET();
String body = http.getString();
Serial.print("RESP SEND code: ");
Serial.print(code);
Serial.print(" | body: ");
Serial.println(body);
http.end();
return (code == 200);
}
bool getV2FromBlynk(int &outV2) {
outV2 = 0;
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ Tidak terkoneksi WiFi saat akan GET V2.");
return false;
}
HTTPClient http;
String url = makeUrlGetV2();
Serial.print("Request GET V2 -> ");
Serial.println(url);
http.begin(url);
int code = http.GET();
String body = http.getString();
Serial.print("RESP GET code: ");
Serial.print(code);
Serial.print(" | body: ");
Serial.println(body);
http.end();
if (code == 200) {
// body biasanya "0" atau "1" atau JSON tergantung; kita ambil angka pertama kalau ada
body.trim();
if (body.length() > 0) {
// extract digits
for (size_t i = 0; i < body.length(); ++i) {
if (isDigit(body.charAt(i))) {
outV2 = body.charAt(i) - '0';
return true;
}
}
}
return false;
}
return false;
}
void applyLedLogic(float suhu) {
int autoLed = (suhu > BATAS_SUHU) ? 1 : 0;
// manual override: jika manualV2 == 1 maka final = 1; jika manualV2 == 0 maka gunakan autoLed
int finalLed = (manualV2 == 1) ? 1 : autoLed;
if (finalLed != ledState) {
ledState = finalLed;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
Serial.print("LED di-set ke: ");
Serial.println(ledState ? "ON" : "OFF");
}
}
void loop() {
unsigned long now = millis();
// 1) Periksa apakah waktunya GET V2 (kontrol manual)
if (now - lastGet >= INTERVAL_GET) {
lastGet = now;
int v2 = 0;
if (getV2FromBlynk(v2)) {
manualV2 = v2 ? 1 : 0;
Serial.print("Manual V2 dari Blynk = ");
Serial.println(manualV2);
} else {
Serial.println("Gagal baca V2 (atau body kosong). Tetap gunakan nilai manual sebelumnya.");
}
}
// 2) Periksa apakah waktunya mengirim sensor ke Blynk
if (now - lastSend >= INTERVAL_SEND) {
lastSend = now;
float suhu = dht.readTemperature();
float hum = dht.readHumidity();
// Filter pembacaan invalid
if (isnan(suhu) || isnan(hum)) {
Serial.println("⚠️ Pembacaan sensor DHT tidak valid (NaN). Lewati kirim.");
// jangan langsung return — lanjutkan loop
} else if (suhu < -10 || suhu > 80) {
// deteksi anomali (mis: simulasi out-of-range)
Serial.print("⚠️ Pembacaan anomali: Suhu=");
Serial.print(suhu);
Serial.println(" °C (abaikan)");
} else {
// kirim data
bool ok = sendSensorToBlynk(suhu, hum);
if (!ok) {
Serial.println("❌ Gagal kirim data ke Blynk (cek koneksi/token).");
} else {
Serial.println("✅ Sukses kirim data ke Blynk.");
}
// update LED berdasarkan suhu & manual
applyLedLogic(suhu);
// tampilkan ringkasan
Serial.print("Ringkasan: Suhu=");
Serial.print(suhu, 2);
Serial.print(" °C | Kelembapan=");
Serial.print(hum, 2);
Serial.print(" % | LED=");
Serial.println(ledState ? "ON" : "OFF");
Serial.println("-------------------------------");
}
}
// sedikit delay kecil supaya CPU yield
delay(50);
}