#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ========= WIFI =========
const char* ssid = "Wokwi-GUEST"; //bisa ganti dengan nama wifi yang ada di sekitar
const char* password = "";
// ========= TELEGRAM =========
#define BOT_TOKEN "8716321370:AAFHRlnOfCs3dUO6Ik50GPEB59JAAmW14KE"
#define CHAT_ID "1870785662"
// ===== PIN SENSOR & BUZZER =====
#define TRIG_PIN 5
#define ECHO_PIN 18
#define BUZZER_PIN 27
// ===== PIN LED INDIKATOR =====
#define LED_HIJAU 25
#define LED_KUNING 26
#define LED_MERAH 33
// ===== LCD =====
LiquidCrystal_I2C lcd(0x27, 16, 2);
// ===== PARAMETER LEVEL =====
const float levelBahaya = 20.0;
const float levelSiaga = 60.0;
const float levelAman = 100.0;
// ===== ANTI FAKE ALARM (5 detik) =====
const int LOOP_DELAY_MS = 500;
const int ALARM_DELAY_MS = 5000;
const int bahayaConfirm = ALARM_DELAY_MS / LOOP_DELAY_MS; // 10x
int bahayaCount = 0;
bool alarmOn = false;
// ===== TELEGRAM INTERVAL =====
const unsigned long SIAGA_REPEAT_MS = 60UL * 60UL * 1000UL; // 1 jam
const unsigned long BAHAYA_REPEAT_MS = 5UL * 60UL * 1000UL; // 5 menit
enum StatusLevel { ST_ERROR, ST_AMAN, ST_NORMAL, ST_SIAGA, ST_BAHAYA };
StatusLevel currentLevel = ST_NORMAL;
StatusLevel lastLevel = ST_NORMAL;
unsigned long lastSiagaSent = 0;
unsigned long lastBahayaSent = 0;
WiFiClientSecure client;
// --- util: URL encode sederhana (spasi & beberapa karakter umum) ---
String urlEncode(const String &s) {
String out = "";
for (size_t i = 0; i < s.length(); i++) {
char c = s[i];
if (c == ' ') out += "%20";
else if (c == '\n') out += "%0A";
else if (c == '\r') {}
else if (c == '!') out += "%21";
else if (c == '#') out += "%23";
else if (c == '%') out += "%25";
else if (c == '&') out += "%26";
else if (c == '+') out += "%2B";
else if (c == '?') out += "%3F";
else if (c == '=') out += "%3D";
else out += c;
}
return out;
}
// --- kirim Telegram via HTTPS GET ---
bool sendTelegram(const String &msg) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi disconnected, skip Telegram.");
return false;
}
client.setInsecure(); // untuk demo, biar gak perlu sertifikat
const char* host = "api.telegram.org";
if (!client.connect(host, 443)) {
Serial.println("Telegram connect failed");
return false;
}
String text = urlEncode(msg);
String url = String("/bot") + BOT_TOKEN + "/sendMessage?chat_id=" + CHAT_ID + "&text=" + text;
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
// baca respon singkat
unsigned long t0 = millis();
while (client.connected() && millis() - t0 < 5000) {
while (client.available()) {
String line = client.readStringUntil('\n');
if (line.startsWith("{\"ok\":true")) {
Serial.println("Telegram sent OK");
return true;
}
}
}
Serial.println("Telegram response timeout / not OK");
return false;
}
// Baca jarak HC-SR04 (cm)
float readDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000UL);
if (duration == 0) return 999.0;
return (duration * 0.0343f) / 2.0f;
}
void setBuzzer(bool on) {
if (on && !alarmOn) {
tone(BUZZER_PIN, 2000);
alarmOn = true;
} else if (!on && alarmOn) {
noTone(BUZZER_PIN);
alarmOn = false;
}
}
void ledsOff() {
digitalWrite(LED_HIJAU, LOW);
digitalWrite(LED_KUNING, LOW);
digitalWrite(LED_MERAH, LOW);
}
void ensureWiFi() {
if (WiFi.status() == WL_CONNECTED) return;
Serial.println("Reconnecting WiFi...");
WiFi.disconnect(true);
WiFi.begin(ssid, password);
unsigned long t0 = millis();
while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) {
delay(300);
Serial.print(".");
}
Serial.println(WiFi.status() == WL_CONNECTED ? "\nWiFi connected!" : "\nWiFi reconnect timeout.");
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_HIJAU, OUTPUT);
pinMode(LED_KUNING, OUTPUT);
pinMode(LED_MERAH, OUTPUT);
ledsOff();
Wire.begin(21, 22);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Sensor Banjir");
lcd.setCursor(0, 1);
lcd.print("Mulai...");
delay(1000);
lcd.clear();
WiFi.begin(ssid, password);
Serial.print("Connecting WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected!");
sendTelegram("SIGMA SIAP HADIR ✅");
}
void loop() {
ensureWiFi();
float distanceCm = readDistanceCm();
const char* statusText = "----";
bool buzzer = false;
ledsOff();
if (distanceCm >= 999.0) {
bahayaCount = 0;
currentLevel = ST_ERROR;
statusText = "ERROR";
buzzer = false;
digitalWrite(LED_MERAH, HIGH);
}
else if (distanceCm <= levelBahaya) {
bahayaCount++;
digitalWrite(LED_MERAH, HIGH);
if (bahayaCount >= bahayaConfirm) {
currentLevel = ST_BAHAYA;
statusText = "BAHAYA!";
buzzer = true;
} else {
currentLevel = ST_SIAGA; // masih cek
statusText = "CEK...";
buzzer = false;
}
}
else if (distanceCm <= levelSiaga) {
bahayaCount = 0;
currentLevel = ST_SIAGA;
statusText = "SIAGA";
buzzer = false;
digitalWrite(LED_KUNING, HIGH);
}
else if (distanceCm >= levelAman) {
bahayaCount = 0;
currentLevel = ST_AMAN;
statusText = "AMAN";
buzzer = false;
digitalWrite(LED_HIJAU, HIGH);
}
else {
bahayaCount = 0;
currentLevel = ST_NORMAL;
statusText = "NORMAL";
buzzer = false;
digitalWrite(LED_HIJAU, HIGH);
}
// ===== TELEGRAM LOGIC =====
unsigned long now = millis();
if (currentLevel != lastLevel) {
if (currentLevel == ST_SIAGA) {
sendTelegram("⚠️ AIR SUNGAI MENDEKATI SENSOR \nJarak: " + String(distanceCm, 1) + " cm");
lastSiagaSent = now;
} else if (currentLevel == ST_BAHAYA) {
sendTelegram("🚨 BAHAYA,AIR SUNGAI MELUAP !\n\n langkah evakuasi yang di sarankan \n 1.Mengumpulkan barang berharga dan makanan.\n 2.Berkumpul bersama warga lain.\n 3.Menuju tempat yang lebih tinggi atau tempat pengungsian.\n 4.Mengikuti arahan petugas dan tetap berada di tempat yang aman.\n\nJarak: " + String(distanceCm, 1) + " cm\nAlarm aktif.");
lastBahayaSent = now;
}
if (currentLevel != ST_SIAGA) lastSiagaSent = 0;
if (currentLevel != ST_BAHAYA) lastBahayaSent = 0;
lastLevel = currentLevel;
}
if (currentLevel == ST_SIAGA) {
if (lastSiagaSent == 0 || (now - lastSiagaSent >= SIAGA_REPEAT_MS)) {
sendTelegram("⚠️ SIAGA (update 1 jam)\nJarak: " + String(distanceCm, 1) + " cm");
lastSiagaSent = now;
}
} else if (currentLevel == ST_BAHAYA) {
if (lastBahayaSent == 0 || (now - lastBahayaSent >= BAHAYA_REPEAT_MS)) {
sendTelegram("🚨 BAHAYA (update 5 menit)\nJarak: " + String(distanceCm, 1) + " cm");
lastBahayaSent = now;
}
}
// ===== Serial =====
Serial.print("Jarak: ");
Serial.print(distanceCm, 1);
Serial.print(" cm | STATUS: ");
Serial.print(statusText);
Serial.print(" | bahayaCount: ");
Serial.print(bahayaCount);
Serial.print("/");
Serial.println(bahayaConfirm);
// ===== LCD =====
lcd.setCursor(0, 0);
lcd.print("Jarak: ");
if (distanceCm >= 999.0) {
lcd.print("---- ");
} else {
char buf[8];
dtostrf(distanceCm, 5, 1, buf);
lcd.print(buf);
}
lcd.print("cm ");
lcd.setCursor(0, 1);
lcd.print("STATUS: ");
lcd.print(statusText);
if (distanceCm <= levelBahaya && distanceCm < 999.0 && bahayaCount < bahayaConfirm) {
int sisa = (bahayaConfirm - bahayaCount) * LOOP_DELAY_MS / 1000;
lcd.print(" ");
lcd.print(sisa);
lcd.print("s ");
} else {
lcd.print(" ");
}
lcd.print(" ");
setBuzzer(buzzer);
delay(LOOP_DELAY_MS);
}