Upload files to "/"
This commit is contained in:
parent
4eabfa8402
commit
2ec3454eee
|
@ -0,0 +1,289 @@
|
|||
#include <WiFi.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <FirebaseESP32.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <time.h>
|
||||
|
||||
#define API_KEY "AIzaSyDCtvZMg-Ma0BCjG3eEpEEgs19EJVBTx90"
|
||||
#define DATABASE_URL "https://floodwatch-cabc5-default-rtdb.asia-southeast1.firebasedatabase.app/"
|
||||
|
||||
String namaSungai = "sungai_bedadung";
|
||||
|
||||
FirebaseData fbdo;
|
||||
FirebaseAuth auth;
|
||||
FirebaseConfig config;
|
||||
|
||||
const char* backendHistoriURL = "https://services-flood.vercel.app/api/histori";
|
||||
const char* backendNotifikasiURL = "https://services-flood.vercel.app/api/notifikasi";
|
||||
|
||||
#define LORA_TX 17
|
||||
#define LORA_RX 16
|
||||
#define M0 25
|
||||
#define M1 26
|
||||
|
||||
#define LED_PIN 15
|
||||
#define BUTTON_PIN 4
|
||||
|
||||
unsigned long lastDataTime = 0;
|
||||
unsigned long lastBackendTime = 0;
|
||||
unsigned long lastThresholdCheck = 0;
|
||||
unsigned long lastDaruratCheck = 0;
|
||||
|
||||
const unsigned long dataInterval = 5000;
|
||||
const unsigned long backendInterval = 60000;
|
||||
const unsigned long thresholdInterval = 10000;
|
||||
const unsigned long daruratInterval = 5000;
|
||||
|
||||
float lastKetinggian = 0;
|
||||
float lastKetinggianDarurat = 0;
|
||||
float nilaiAmbangBatas = 150.0;
|
||||
float tinggiSensorDariDasar = 200.0;
|
||||
|
||||
const float ambangKenaikanDarurat = 30.0; // Lonjakan ketinggian cepat dalam 5 detik
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
pinMode(M0, OUTPUT);
|
||||
pinMode(M1, OUTPUT);
|
||||
digitalWrite(M0, LOW);
|
||||
digitalWrite(M1, LOW);
|
||||
Serial2.begin(9600, SERIAL_8N1, LORA_RX, LORA_TX);
|
||||
delay(500);
|
||||
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
if (digitalRead(BUTTON_PIN) == LOW) {
|
||||
WiFiManager wm;
|
||||
wm.resetSettings();
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFiManager wm;
|
||||
wm.setTimeout(180);
|
||||
if (!wm.autoConnect("FloodWatch-Receiver")) {
|
||||
Serial.println("Failed to connect and hit timeout");
|
||||
delay(3000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
Serial.println("Connected to WiFi: " + WiFi.SSID());
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
|
||||
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
|
||||
|
||||
config.api_key = API_KEY;
|
||||
config.database_url = DATABASE_URL;
|
||||
auth.user.email = "sungaibedadung@gmail.com";
|
||||
auth.user.password = "123456";
|
||||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
|
||||
Serial.println("📡 Receiver LoRa Flood Detection Ready");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
if (Serial2.available()) {
|
||||
String incoming = Serial2.readStringUntil('\n');
|
||||
incoming.trim();
|
||||
|
||||
Serial.print("📩 Pesan masuk: ");
|
||||
Serial.println(incoming);
|
||||
|
||||
if (incoming.startsWith("DATA:")) {
|
||||
processSensorData(incoming);
|
||||
lastDataTime = currentMillis;
|
||||
} else if (incoming.startsWith("ACK:")) {
|
||||
Serial.println("✅ Sender menerima update kalibrasi");
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMillis - lastThresholdCheck >= thresholdInterval) {
|
||||
lastThresholdCheck = currentMillis;
|
||||
checkFirebaseThreshold();
|
||||
}
|
||||
|
||||
if (currentMillis - lastBackendTime >= backendInterval) {
|
||||
lastBackendTime = currentMillis;
|
||||
sendToBackend(lastKetinggian);
|
||||
}
|
||||
|
||||
checkKenaikanDarurat(); // 🔥 Tambahan untuk deteksi mendadak
|
||||
updateLEDStatus();
|
||||
checkResetButton();
|
||||
}
|
||||
|
||||
void processSensorData(String data) {
|
||||
int kStart = data.indexOf("KETINGGIAN=");
|
||||
int hStart = data.indexOf("HUJAN=");
|
||||
int endData = data.indexOf(';', hStart);
|
||||
|
||||
if (kStart != -1 && hStart != -1 && endData != -1) {
|
||||
float ketinggian = data.substring(kStart + 11, hStart - 1).toFloat();
|
||||
int hujan = data.substring(hStart + 6, endData).toInt();
|
||||
|
||||
lastKetinggian = ketinggian;
|
||||
|
||||
Serial.println("📊 Data Sensor:");
|
||||
Serial.println(" Ketinggian: " + String(ketinggian) + " cm");
|
||||
Serial.println(" Hujan: " + String(hujan) + "%");
|
||||
|
||||
updateFirebaseData(ketinggian, hujan);
|
||||
}
|
||||
}
|
||||
|
||||
void checkFirebaseThreshold() {
|
||||
String pathTinggi = "/" + namaSungai + "/kalibrasi/tinggiSensor";
|
||||
String pathAmbang = "/" + namaSungai + "/threshold/nilai";
|
||||
bool needUpdate = false;
|
||||
|
||||
if (Firebase.getFloat(fbdo, pathTinggi) && fbdo.httpCode() == 200) {
|
||||
float newTinggi = fbdo.floatData();
|
||||
if (newTinggi != tinggiSensorDariDasar) {
|
||||
tinggiSensorDariDasar = newTinggi;
|
||||
Serial.println("🔄 Tinggi sensor diperbarui: " + String(newTinggi));
|
||||
needUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Firebase.getFloat(fbdo, pathAmbang) && fbdo.httpCode() == 200) {
|
||||
float newAmbang = fbdo.floatData();
|
||||
if (newAmbang != nilaiAmbangBatas) {
|
||||
nilaiAmbangBatas = newAmbang;
|
||||
Serial.println("🔄 Ambang batas diperbarui: " + String(newAmbang));
|
||||
needUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needUpdate) {
|
||||
String cmd = "SETTING:TINGGI=" + String(tinggiSensorDariDasar, 1) +
|
||||
",BATAS=" + String(nilaiAmbangBatas, 1) + ";";
|
||||
Serial2.println(cmd);
|
||||
Serial.println("📤 Mengirim kalibrasi: " + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void updateFirebaseData(float ketinggian, int hujan) {
|
||||
String path = "/" + namaSungai;
|
||||
|
||||
Firebase.setFloat(fbdo, path + "/ketinggian", ketinggian);
|
||||
Firebase.setInt(fbdo, path + "/hujan", hujan);
|
||||
}
|
||||
|
||||
void sendToBackend(float ketinggian) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.println("⚠ WiFi tidak terhubung");
|
||||
return;
|
||||
}
|
||||
|
||||
String level = "AMAN";
|
||||
if (ketinggian >= nilaiAmbangBatas) {
|
||||
level = "BAHAYA";
|
||||
} else if (ketinggian >= nilaiAmbangBatas * 0.7) {
|
||||
level = "WASPADA";
|
||||
}
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(backendHistoriURL);
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
|
||||
String jsonHistori = "{\"sungai\":\"" + namaSungai +
|
||||
"\",\"ketinggian\":" + String(ketinggian, 1) +
|
||||
",\"timestamp\":" + String(now) +
|
||||
",\"level\":\"" + level + "\"}";
|
||||
|
||||
int httpCode = http.POST(jsonHistori);
|
||||
Serial.printf(httpCode > 0 ? "✅ Histori terkirim (HTTP %d)\n" : "❌ Gagal kirim histori (HTTP %d)\n", httpCode);
|
||||
http.end();
|
||||
|
||||
if (level == "WASPADA" || level == "BAHAYA") {
|
||||
http.begin(backendNotifikasiURL);
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
|
||||
String jsonNotif = "{\"sungai\":\"" + namaSungai +
|
||||
"\",\"ketinggian\":" + String(ketinggian, 1) +
|
||||
",\"timestamp\":" + String(now) +
|
||||
",\"level\":\"" + level + "\"}";
|
||||
|
||||
int notifCode = http.POST(jsonNotif);
|
||||
Serial.printf(notifCode > 0 ? "📣 Notifikasi terkirim (HTTP %d)\n" : "⚠ Gagal kirim notifikasi (HTTP %d)\n", notifCode);
|
||||
http.end();
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 Deteksi Kenaikan Cepat Air
|
||||
void checkKenaikanDarurat() {
|
||||
unsigned long now = millis();
|
||||
if (now - lastDaruratCheck >= daruratInterval) {
|
||||
float delta = lastKetinggian - lastKetinggianDarurat;
|
||||
|
||||
if (delta >= ambangKenaikanDarurat && lastKetinggian >= nilaiAmbangBatas * 0.7) {
|
||||
Serial.println("🚨 Deteksi banjir mendadak! Naik cepat.");
|
||||
kirimNotifikasiDarurat();
|
||||
}
|
||||
|
||||
lastKetinggianDarurat = lastKetinggian;
|
||||
lastDaruratCheck = now;
|
||||
}
|
||||
}
|
||||
|
||||
// 🔔 Kirim Notifikasi Darurat Langsung
|
||||
void kirimNotifikasiDarurat() {
|
||||
if (WiFi.status() != WL_CONNECTED) return;
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(backendNotifikasiURL);
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
|
||||
String jsonNotif = "{\"sungai\":\"" + namaSungai +
|
||||
"\",\"ketinggian\":" + String(lastKetinggian, 1) +
|
||||
",\"timestamp\":" + String(now) +
|
||||
",\"level\":\"DARURAT\"}";
|
||||
|
||||
int code = http.POST(jsonNotif);
|
||||
Serial.printf(code > 0 ? "🚨 Notif DARURAT dikirim (HTTP %d)\n" : "❌ Gagal kirim notif darurat (HTTP %d)\n", code);
|
||||
http.end();
|
||||
}
|
||||
|
||||
void updateLEDStatus() {
|
||||
static unsigned long lastBlink = 0;
|
||||
static bool ledState = false;
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
} else {
|
||||
unsigned long now = millis();
|
||||
if (now - lastBlink >= 500) {
|
||||
lastBlink = now;
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_PIN, ledState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkResetButton() {
|
||||
static unsigned long lastPress = 0;
|
||||
|
||||
if (digitalRead(BUTTON_PIN) == LOW && millis() - lastPress > 200) {
|
||||
lastPress = millis();
|
||||
Serial.println("🔄 Tombol reset WiFi ditekan");
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
WiFiManager wm;
|
||||
wm.resetSettings();
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
#include <HardwareSerial.h>
|
||||
|
||||
// -------------------- Pin Konfigurasi --------------------
|
||||
#define LORA_TX 17
|
||||
#define LORA_RX 16
|
||||
#define M0 25
|
||||
#define M1 26
|
||||
#define TRIG_PIN 5
|
||||
#define ECHO_PIN 18
|
||||
#define RAIN_SENSOR_PIN 34
|
||||
#define BUZZER_PIN 27
|
||||
|
||||
// -------------------- Variabel Sensor --------------------
|
||||
float ketinggianAir;
|
||||
int rainPercent;
|
||||
|
||||
// -------------------- Kalibrasi --------------------
|
||||
float tinggiSensorDariDasar = 200.0;
|
||||
float batasAmanKetinggian = 150.0;
|
||||
|
||||
// -------------------- Timing & Filter --------------------
|
||||
unsigned long lastSendTime = 0;
|
||||
const unsigned long sendInterval = 2000;
|
||||
|
||||
#define FILTER_SAMPLES 5
|
||||
float distanceSamples[FILTER_SAMPLES];
|
||||
int currentSample = 0;
|
||||
|
||||
// -------------------- Buzzer --------------------
|
||||
unsigned long lastBuzzerTime = 0;
|
||||
const unsigned long buzzerInterval = 200;
|
||||
bool buzzerState = false;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
pinMode(M0, OUTPUT);
|
||||
pinMode(M1, OUTPUT);
|
||||
digitalWrite(M0, LOW);
|
||||
digitalWrite(M1, LOW);
|
||||
Serial2.begin(9600, SERIAL_8N1, LORA_RX, LORA_TX);
|
||||
delay(500);
|
||||
|
||||
Serial.println("🚀 Sender LoRa Flood Detection Ready");
|
||||
|
||||
pinMode(TRIG_PIN, OUTPUT);
|
||||
pinMode(ECHO_PIN, INPUT);
|
||||
pinMode(RAIN_SENSOR_PIN, INPUT);
|
||||
pinMode(BUZZER_PIN, OUTPUT);
|
||||
digitalWrite(BUZZER_PIN, LOW);
|
||||
|
||||
for (int i = 0; i < FILTER_SAMPLES; i++) {
|
||||
distanceSamples[i] = tinggiSensorDariDasar;
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
processIncomingMessages();
|
||||
|
||||
float distance = readUltrasonic();
|
||||
ketinggianAir = tinggiSensorDariDasar - distance;
|
||||
ketinggianAir = constrain(ketinggianAir, 0, tinggiSensorDariDasar);
|
||||
|
||||
rainPercent = readRainSensor();,
|
||||
|
||||
controlBuzzer(currentMillis);
|
||||
|
||||
if (currentMillis - lastSendTime >= sendInterval) {
|
||||
lastSendTime = currentMillis;
|
||||
sendSensorData();
|
||||
}
|
||||
|
||||
delay(50);
|
||||
}
|
||||
|
||||
void processIncomingMessages() {
|
||||
if (Serial2.available()) {
|
||||
String incoming = Serial2.readStringUntil('\n');
|
||||
incoming.trim();
|
||||
|
||||
Serial.print("📩 Pesan masuk: ");
|
||||
Serial.println(incoming);
|
||||
|
||||
if (incoming.startsWith("SETTING:")) {
|
||||
int tStart = incoming.indexOf("TINGGI=");
|
||||
int bStart = incoming.indexOf("BATAS=");
|
||||
int endCmd = incoming.indexOf(';');
|
||||
|
||||
if (tStart != -1 && bStart != -1 && endCmd != -1) {
|
||||
float newTinggi = incoming.substring(tStart + 7, bStart - 1).toFloat();
|
||||
float newBatas = incoming.substring(bStart + 6, endCmd).toFloat();
|
||||
|
||||
if (newTinggi > 0 && newBatas > 0) {
|
||||
tinggiSensorDariDasar = newTinggi;
|
||||
batasAmanKetinggian = newBatas;
|
||||
|
||||
Serial.println("🔧 Kalibrasi diperbarui:");
|
||||
Serial.println(" Tinggi Sensor: " + String(tinggiSensorDariDasar) + " cm");
|
||||
Serial.println(" Batas Aman: " + String(batasAmanKetinggian) + " cm");
|
||||
|
||||
Serial2.println("ACK:SETTING_OK;");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float readUltrasonic() {
|
||||
digitalWrite(TRIG_PIN, LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(TRIG_PIN, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(TRIG_PIN, LOW);
|
||||
|
||||
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
|
||||
|
||||
if (duration == 0) {
|
||||
Serial.println("⚠ Error: Sensor ultrasonik tidak merespon");
|
||||
return tinggiSensorDariDasar;
|
||||
}
|
||||
|
||||
float distance = duration * 0.034 / 2;
|
||||
distanceSamples[currentSample] = distance;
|
||||
currentSample = (currentSample + 1) % FILTER_SAMPLES;
|
||||
|
||||
float avgDistance = 0;
|
||||
for (int i = 0; i < FILTER_SAMPLES; i++) {
|
||||
avgDistance += distanceSamples[i];
|
||||
}
|
||||
return avgDistance / FILTER_SAMPLES;
|
||||
}
|
||||
|
||||
int readRainSensor() {
|
||||
int rawValue = analogRead(RAIN_SENSOR_PIN);
|
||||
int percent = map(rawValue, 4095, 0, 0, 100);
|
||||
return constrain(percent, 0, 100);
|
||||
}
|
||||
|
||||
void controlBuzzer(unsigned long currentTime) {
|
||||
if (ketinggianAir >= batasAmanKetinggian) {
|
||||
if (currentTime - lastBuzzerTime >= buzzerInterval) {
|
||||
lastBuzzerTime = currentTime;
|
||||
buzzerState = !buzzerState;
|
||||
digitalWrite(BUZZER_PIN, buzzerState ? HIGH : LOW);
|
||||
}
|
||||
} else {
|
||||
digitalWrite(BUZZER_PIN, LOW);
|
||||
buzzerState = false;
|
||||
}
|
||||
}
|
||||
|
||||
void sendSensorData() {
|
||||
String dataStr = "DATA:KETINGGIAN=" + String(ketinggianAir, 1) +
|
||||
",HUJAN=" + String(rainPercent) + ";";
|
||||
|
||||
Serial2.println(dataStr);
|
||||
Serial.println("📤 Mengirim data: " + dataStr);
|
||||
}
|
Loading…
Reference in New Issue