Upload files to "/"
This commit is contained in:
commit
6d94ef6230
|
@ -0,0 +1,52 @@
|
|||
const { Client, LocalAuth } = require('whatsapp-web.js');
|
||||
const qrcode = require('qrcode-terminal');
|
||||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
|
||||
// Middleware untuk meng-parse JSON request body
|
||||
app.use(bodyParser.json());
|
||||
|
||||
// Inisialisasi client WhatsApp
|
||||
const client = new Client({
|
||||
authStrategy: new LocalAuth(),
|
||||
});
|
||||
|
||||
// Menampilkan QR Code saat pertama kali login
|
||||
client.on('qr', (qr) => {
|
||||
qrcode.generate(qr, { small: true });
|
||||
});
|
||||
|
||||
// Setelah terhubung
|
||||
client.on('ready', () => {
|
||||
console.log('WhatsApp Web is ready');
|
||||
});
|
||||
|
||||
// Service untuk mengirim pesan
|
||||
app.post('/send-message', (req, res) => {
|
||||
const { phone, message } = req.body;
|
||||
|
||||
if (!phone || !message) {
|
||||
return res.status(400).send('Phone number and message are required!');
|
||||
}
|
||||
|
||||
// Mengirim pesan
|
||||
client.sendMessage(`${phone}@c.us`, message)
|
||||
.then((response) => {
|
||||
res.status(200).send('Message sent successfully!');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
res.status(500).send('Failed to send message');
|
||||
});
|
||||
});
|
||||
|
||||
// Jalankan server
|
||||
app.listen(port, () => {
|
||||
console.log(`WhatsApp API service running on http://localhost:${port}`);
|
||||
});
|
||||
|
||||
// Log in to WhatsApp Web
|
||||
client.initialize();
|
|
@ -0,0 +1,412 @@
|
|||
#include <WiFi.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <Firebase_ESP_Client.h>
|
||||
#include <ESP32Servo.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
#include <Wire.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
// === KREDENSIAL FIREBASE ===
|
||||
#define API_KEY "AIzaSyBRT9jVU0jbLLri5ZWFgELiP-MwdWqJqGY"
|
||||
#define DATABASE_URL "https://palang-pintu-1ee1b-default-rtdb.asia-southeast1.firebasedatabase.app/"
|
||||
#define LEGACY_TOKEN "ii4jFWAjUalW2zkYddwhzk8313hD5TLsewohcvdR"
|
||||
|
||||
// === PIN SENSOR DAN KOMPONEN ===
|
||||
#define TRIG1 14
|
||||
#define ECHO1 27
|
||||
#define TRIG2 25
|
||||
#define ECHO2 26
|
||||
#define SERVO_PIN 18
|
||||
#define BUZZER_PIN 12
|
||||
#define LED_AMAN 32
|
||||
#define LED_BAHAYA 33
|
||||
#define PIEZO_PIN1 34
|
||||
#define BUTTON_UP 23
|
||||
#define BUTTON_DOWN 19
|
||||
#define RXD2 16
|
||||
#define TXD2 17
|
||||
|
||||
// === OBJEK & VARIABEL GLOBAL ===
|
||||
FirebaseData fbdo;
|
||||
FirebaseAuth auth;
|
||||
FirebaseConfig config;
|
||||
Servo servoJalur1;
|
||||
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
||||
|
||||
unsigned long lastUpdate = 0;
|
||||
unsigned long lastSerialPrint = 0;
|
||||
const unsigned long interval = 5000;
|
||||
unsigned long intervalJeda = 5000;
|
||||
|
||||
bool isOfflineMode = false;
|
||||
bool keretaTerdeteksi = false;
|
||||
bool keretaLewat = false;
|
||||
|
||||
int upClickCount = 0;
|
||||
int downClickCount = 0;
|
||||
bool lastButtonUpState = HIGH;
|
||||
bool lastButtonDownState = HIGH;
|
||||
// Flag to track if the waiting message for Jalur 2 has been sent
|
||||
bool waitingMessageSent = false;
|
||||
// Flag to track if the "Kereta telah lewat di Jalur 1!" message has been sent
|
||||
bool keretaLewatMessageSent = false;
|
||||
|
||||
int tresholdUltrasonik = 50; // Default 50 cm
|
||||
int tresholdPiezo = 300; // Default 300
|
||||
String phoneNumber = "6282221448622"; // Nomor telepon yang akan dihubungi
|
||||
String serviceURL = "http://192.168.37.201:3000/send-message"; // Default service URL
|
||||
|
||||
|
||||
|
||||
// Fungsi untuk mengambil status_kereta dari Firebase dan mengontrol palang
|
||||
void fetchStatusKereta() {
|
||||
// Coba ambil status kereta dari Firebase
|
||||
if (Firebase.RTDB.getBool(&fbdo, "/status_kereta")) {
|
||||
if (fbdo.dataType() == "boolean") { // Cek apakah tipe data adalah boolean
|
||||
bool statusKereta = fbdo.boolData(); // Ambil nilai boolean dari Firebase
|
||||
|
||||
// Hanya tampilkan status jika ada pembaruan
|
||||
static bool lastStatusKereta = false; // Variabel untuk menyimpan status terakhir
|
||||
if (statusKereta != lastStatusKereta) { // Cek apakah status berubah
|
||||
Serial.print("[INFO] Status kereta dari Firebase: ");
|
||||
Serial.println(statusKereta ? "DITUTUP" : "DIBUKA");
|
||||
lastStatusKereta = statusKereta; // Update status terakhir
|
||||
}
|
||||
|
||||
// Lakukan aksi berdasarkan status kereta
|
||||
if (statusKereta) {
|
||||
// Status kereta true, tutup palang
|
||||
servoJalur1.write(90); // Tutup palang
|
||||
digitalWrite(LED_BAHAYA, HIGH); // LED merah menyala
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH); // Bunyi buzzer
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("PALANG DITUTUP");
|
||||
} else {
|
||||
// Status kereta false, buka palang
|
||||
servoJalur1.write(0); // Buka palang
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW); // Matikan buzzer
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("PALANG DIBUKA");
|
||||
}
|
||||
} else {
|
||||
// Jika tipe data bukan boolean
|
||||
Serial.print("[ERROR] Data bukan boolean: ");
|
||||
Serial.println(fbdo.dataType()); // Tampilkan tipe data yang salah
|
||||
}
|
||||
} else {
|
||||
// Jika gagal mendapatkan data dari Firebase
|
||||
Serial.print("[ERROR] Gagal mendapatkan status kereta: ");
|
||||
Serial.println(fbdo.errorReason()); // Menampilkan alasan error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// === AMBIL DATA THRESHOLD DARI FIREBASE ===
|
||||
void updateThresholdFromFirebase() {
|
||||
if (Firebase.RTDB.getInt(&fbdo, "/treshold/ultrasonik") && fbdo.dataType() == "int") {
|
||||
tresholdUltrasonik = fbdo.intData();
|
||||
Serial.print("Treshold Ultrasonik diperbarui: ");
|
||||
Serial.println(tresholdUltrasonik);
|
||||
}
|
||||
|
||||
if (Firebase.RTDB.getInt(&fbdo, "/treshold/piezo") && fbdo.dataType() == "int") {
|
||||
tresholdPiezo = fbdo.intData();
|
||||
Serial.print("Treshold Piezo diperbarui: ");
|
||||
Serial.println(tresholdPiezo);
|
||||
}
|
||||
|
||||
if (Firebase.RTDB.getInt(&fbdo, "/treshold/interval_jeda") && fbdo.dataType() == "int") {
|
||||
intervalJeda = fbdo.intData() * 1000;
|
||||
Serial.print("Interval Jeda diperbarui: ");
|
||||
Serial.println(intervalJeda);
|
||||
}
|
||||
}
|
||||
|
||||
void sendWAAlert(String message) {
|
||||
HTTPClient http;
|
||||
http.begin(serviceURL); // Gunakan serviceURL yang telah disesuaikan
|
||||
|
||||
String payload = "{\"phone\": \"" + phoneNumber + "\", \"message\": \"" + message + "\"}"; // Gunakan phoneNumber langsung
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
|
||||
// Kirim permintaan POST
|
||||
int httpResponseCode = http.POST(payload);
|
||||
|
||||
if (httpResponseCode > 0) {
|
||||
// Menyediakan feedback sukses
|
||||
Serial.println("Pesan WhatsApp terkirim ke " + phoneNumber + ": " + String(httpResponseCode));
|
||||
} else {
|
||||
// Menyediakan feedback gagal
|
||||
Serial.println("Gagal mengirim pesan WhatsApp ke " + phoneNumber + ": " + String(httpResponseCode));
|
||||
Serial.println("Error: " + http.errorToString(httpResponseCode));
|
||||
}
|
||||
|
||||
http.end(); // Tutup permintaan HTTP
|
||||
}
|
||||
|
||||
|
||||
|
||||
// === SETUP ===
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); // komunikasi ke ESP2
|
||||
|
||||
servoJalur1.setPeriodHertz(50);
|
||||
servoJalur1.attach(SERVO_PIN);
|
||||
|
||||
Wire.begin(22, 21);
|
||||
lcd.init();
|
||||
lcd.backlight();
|
||||
|
||||
pinMode(TRIG1, OUTPUT);
|
||||
pinMode(ECHO1, INPUT);
|
||||
pinMode(TRIG2, OUTPUT);
|
||||
pinMode(ECHO2, INPUT);
|
||||
pinMode(PIEZO_PIN1, INPUT);
|
||||
pinMode(BUZZER_PIN, OUTPUT);
|
||||
pinMode(LED_AMAN, OUTPUT);
|
||||
pinMode(LED_BAHAYA, OUTPUT);
|
||||
pinMode(BUTTON_UP, INPUT_PULLUP);
|
||||
pinMode(BUTTON_DOWN, INPUT_PULLUP);
|
||||
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print("Menghubungkan...");
|
||||
Serial.println("Menghubungkan ke WiFi...");
|
||||
|
||||
// WiFiManager untuk konfigurasi URL
|
||||
WiFiManager wm;
|
||||
WiFiManagerParameter custom_service_url("service_url", "Service URL", serviceURL.c_str(), 40); // Ukuran maksimal 40 karakter
|
||||
wm.addParameter(&custom_service_url); // Menambahkan parameter
|
||||
|
||||
wm.setTimeout(60);
|
||||
if (!wm.autoConnect("PALANG 1-Setup")) {
|
||||
Serial.println("Gagal konek WiFi. Mode offline.");
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("Mode Offline");
|
||||
isOfflineMode = true; // Set mode offline
|
||||
delay(2000);
|
||||
} else {
|
||||
Serial.println("WiFi Terhubung!");
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("WiFi Terhubung");
|
||||
delay(2000);
|
||||
|
||||
// Ambil URL yang dimasukkan pengguna
|
||||
serviceURL = custom_service_url.getValue(); // Ambil URL yang dikonfigurasi
|
||||
Serial.println("Service URL: " + serviceURL); // Debug URL yang diambil
|
||||
|
||||
// Konfigurasi Firebase jika diperlukan
|
||||
config.api_key = API_KEY;
|
||||
config.database_url = DATABASE_URL;
|
||||
config.signer.tokens.legacy_token = LEGACY_TOKEN;
|
||||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
updateThresholdFromFirebase(); // Update threshold from Firebase
|
||||
}
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("PALANG PINTAR");
|
||||
Serial.println("Sistem Siap: PALANG PINTAR");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Fungsi utama yang berjalan di loop
|
||||
void loop() {
|
||||
// Baca sensor Ultrasonik 1 untuk mendeteksi kereta
|
||||
digitalWrite(TRIG1, LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(TRIG1, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(TRIG1, LOW);
|
||||
long duration1 = pulseIn(ECHO1, HIGH);
|
||||
float distance1 = duration1 * 0.034 / 2; // Menghitung jarak
|
||||
|
||||
// Baca sensor Ultrasonik 2
|
||||
digitalWrite(TRIG2, LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(TRIG2, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(TRIG2, LOW);
|
||||
long duration2 = pulseIn(ECHO2, HIGH);
|
||||
float distance2 = duration2 * 0.034 / 2; // Menghitung jarak
|
||||
|
||||
// Baca sensor Piezo
|
||||
int piezo1Val = analogRead(PIEZO_PIN1);
|
||||
|
||||
// Menampilkan status sensor ke Serial Monitor setiap interval tertentu
|
||||
if (millis() - lastSerialPrint >= interval) {
|
||||
lastSerialPrint = millis();
|
||||
Serial.println("===== STATUS SENSOR =====");
|
||||
Serial.print("Ultrasonik 1: "); Serial.println(distance1);
|
||||
Serial.print("Ultrasonik 2: "); Serial.println(distance2);
|
||||
Serial.print("Piezo1: "); Serial.println(piezo1Val);
|
||||
}
|
||||
|
||||
// === Ambil Status Kereta secara Berkala dari Firebase ===
|
||||
fetchStatusKereta(); // Fungsi yang memeriksa status_kereta setiap interval dan mengontrol palang
|
||||
|
||||
// === Deteksi Kereta Masuk (Jalur 1) ===
|
||||
if (distance1 < tresholdUltrasonik && piezo1Val > tresholdPiezo && !keretaTerdeteksi) {
|
||||
// Periksa status_kereta di Firebase
|
||||
if (Firebase.RTDB.getBool(&fbdo, "/status_kereta")) {
|
||||
bool statusKereta = fbdo.boolData(); // status_kereta (perintah umum)
|
||||
|
||||
if (!statusKereta) { // Hanya tutup palang jika status_kereta adalah false
|
||||
digitalWrite(LED_BAHAYA, HIGH);
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH); // Bunyi buzzer
|
||||
servoJalur1.write(90); // Tutup palang Jalur 1
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("KERETA DATANG");
|
||||
sendWAAlert("Peringatan: Kereta datang di Jalur 1!"); // Kirim pesan WA
|
||||
Serial.println("[INFO] Kereta terdeteksi di Jalur 1 - Palang DITUTUP");
|
||||
|
||||
// Update status_kereta di Firebase
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta", true); // Update status kereta menjadi true
|
||||
|
||||
// Kirim perintah ke ESP Jalur 2 untuk tutup palang jika dalam mode offline
|
||||
if (isOfflineMode) {
|
||||
Serial2.write('0'); // Perintah tutup ke ESP Jalur 2
|
||||
}
|
||||
|
||||
// Update status_kereta_jalur1 di Firebase
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta_jalur1", true); // Update status Jalur 1
|
||||
|
||||
keretaTerdeteksi = true;
|
||||
keretaLewat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// === Cek Kereta Lewat (Jalur 1) ===
|
||||
if (keretaTerdeteksi && distance2 < tresholdUltrasonik) {
|
||||
keretaLewat = true;
|
||||
}
|
||||
|
||||
// Kirim pesan WA hanya sekali jika status_kereta_jalur2 TRUE
|
||||
if (keretaTerdeteksi && keretaLewat && distance2 > tresholdUltrasonik) {
|
||||
// Update status_kereta_jalur1 menjadi false setelah kereta lewat
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta_jalur1", false); // Status Jalur 1 menjadi false
|
||||
|
||||
// Kirim pesan "Kereta telah lewat di Jalur 1!" hanya sekali
|
||||
if (!keretaLewatMessageSent) {
|
||||
sendWAAlert("Peringatan: Kereta telah lewat di Jalur 1!"); // Kirim pesan WA
|
||||
keretaLewatMessageSent = true; // Set flag to prevent sending multiple messages
|
||||
Serial.println("[INFO] Kereta sudah lewat - Pesan telah dikirim.");
|
||||
}
|
||||
|
||||
// Periksa status_kereta_jalur2
|
||||
if (Firebase.RTDB.getBool(&fbdo, "/status_kereta_jalur2")) {
|
||||
bool statusKeretaJalur2 = fbdo.boolData(); // Cek status_kereta_jalur2
|
||||
|
||||
if (statusKeretaJalur2 && !waitingMessageSent) { // Jika status_kereta_jalur2 adalah true, kirim pesan menunggu
|
||||
sendWAAlert("Peringatan: Menunggu kereta 2 lewat!"); // Kirim pesan WA
|
||||
Serial.println("[INFO] Menunggu kereta 2 lewat...");
|
||||
waitingMessageSent = true; // Set flag to true to prevent multiple messages
|
||||
}
|
||||
|
||||
// Cek jika status_kereta adalah false dan status_kereta_jalur2 juga false
|
||||
if (!statusKeretaJalur2) {
|
||||
bool statusKereta = fbdo.boolData(); // Cek status_kereta global
|
||||
|
||||
if (!statusKereta) { // Hanya buka palang jika status_kereta adalah false
|
||||
servoJalur1.write(0); // Buka palang Jalur 1
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW); // Matikan buzzer
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("KERETA LEWAT");
|
||||
|
||||
Serial.println("[INFO] Kereta sudah lewat - Palang DIBUKA");
|
||||
|
||||
// Update status_kereta di Firebase
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta", false); // Update status kereta menjadi false
|
||||
|
||||
// Kirim perintah ke ESP Jalur 2 untuk membuka palang jika dalam mode offline
|
||||
if (isOfflineMode) {
|
||||
Serial2.write('1'); // Perintah buka ke ESP Jalur 2
|
||||
}
|
||||
|
||||
keretaTerdeteksi = false;
|
||||
keretaLewat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Manual Control: Tombol UP ===
|
||||
bool currentUp = digitalRead(BUTTON_UP);
|
||||
if (currentUp == LOW && lastButtonUpState == HIGH) { // Deteksi tombol ditekan
|
||||
servoJalur1.write(0); // Buka palang
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW); // Matikan buzzer
|
||||
Serial.println("[MANUAL] Palang DITUTUP (1x klik)");
|
||||
|
||||
if (!isOfflineMode) {
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta", false); // Update status ke Firebase
|
||||
}
|
||||
|
||||
// Kirim perintah ke ESP Jalur 2 jika dalam mode offline
|
||||
if (isOfflineMode) {
|
||||
Serial2.write('1'); // Perintah tutup ke ESP Jalur 2
|
||||
}
|
||||
|
||||
// Reset hitungan setelah aksi
|
||||
// No need for upClickCount here anymore
|
||||
}
|
||||
lastButtonUpState = currentUp;
|
||||
|
||||
// === Manual Control: Tombol DOWN ===
|
||||
bool currentDown = digitalRead(BUTTON_DOWN);
|
||||
if (currentDown == LOW && lastButtonDownState == HIGH) { // Deteksi tombol ditekan
|
||||
servoJalur1.write(90); // Tutup palang
|
||||
digitalWrite(LED_BAHAYA, HIGH);
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH); // Bunyi buzzer
|
||||
Serial.println("[MANUAL] Palang DIBUKA (1x klik)");
|
||||
|
||||
if (!isOfflineMode) {
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta", true); // Update status ke Firebase
|
||||
}
|
||||
|
||||
// Kirim perintah ke ESP Jalur 2 jika dalam mode offline
|
||||
if (isOfflineMode) {
|
||||
Serial2.write('0'); // Perintah buka ke ESP Jalur 2
|
||||
}
|
||||
|
||||
// Reset hitungan setelah aksi
|
||||
// No need for downClickCount here anymore
|
||||
}
|
||||
lastButtonDownState = currentDown;
|
||||
|
||||
|
||||
// === Terima sinyal dari ESP Jalur 2 === (Mode Offline)
|
||||
if (isOfflineMode && Serial2.available() > 0) {
|
||||
char incomingByte = Serial2.read();
|
||||
if (incomingByte == '0') { // Perintah tutup dari ESP Jalur 2
|
||||
servoJalur1.write(90); // Tutup palang
|
||||
digitalWrite(LED_BAHAYA, HIGH);
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH);
|
||||
Serial.println("[ESP2] Sinyal diterima - Palang DITUTUP oleh ESP2");
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("ESP2: PALANG TUTUP");
|
||||
}
|
||||
if (incomingByte == '1') { // Perintah buka dari ESP Jalur 2
|
||||
servoJalur1.write(0); // Buka palang
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW);
|
||||
Serial.println("[ESP2] Sinyal diterima - Palang DIBUKA oleh ESP2");
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("ESP2: PALANG BUKA");
|
||||
}
|
||||
}
|
||||
|
||||
delay(500); // jeda agar loop tidak terlalu cepat
|
||||
}
|
|
@ -0,0 +1,360 @@
|
|||
#include <WiFi.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <Firebase_ESP_Client.h>
|
||||
#include <ESP32Servo.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
#include <Wire.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
// === KREDENSIAL FIREBASE ===
|
||||
// === KREDENSIAL FIREBASE ===
|
||||
#define API_KEY "AIzaSyBRT9jVU0jbLLri5ZWFgELiP-MwdWqJqGY"
|
||||
#define DATABASE_URL "https://palang-pintu-1ee1b-default-rtdb.asia-southeast1.firebasedatabase.app/"
|
||||
#define LEGACY_TOKEN "ii4jFWAjUalW2zkYddwhzk8313hD5TLsewohcvdR"
|
||||
|
||||
// === PIN SENSOR DAN KOMPONEN ===
|
||||
#define TRIG1 14
|
||||
#define ECHO1 27
|
||||
#define TRIG2 25
|
||||
#define ECHO2 26
|
||||
#define SERVO_PIN 18
|
||||
#define BUZZER_PIN 12
|
||||
#define LED_AMAN 23
|
||||
#define LED_BAHAYA 32
|
||||
#define PIEZO_PIN1 34
|
||||
#define RXD2 16
|
||||
#define TXD2 17
|
||||
|
||||
// === OBJEK & VARIABEL GLOBAL ===
|
||||
FirebaseData fbdo;
|
||||
FirebaseAuth auth;
|
||||
FirebaseConfig config;
|
||||
Servo servoJalur1;
|
||||
LiquidCrystal_I2C lcd(0x27, 16, 2);
|
||||
|
||||
unsigned long lastUpdate = 0;
|
||||
unsigned long lastSerialPrint = 0;
|
||||
const unsigned long interval = 5000;
|
||||
unsigned long intervalJeda = 5000;
|
||||
|
||||
bool isOfflineMode = false;
|
||||
bool keretaTerdeteksi = false;
|
||||
bool keretaLewat = false;
|
||||
|
||||
int upClickCount = 0;
|
||||
int downClickCount = 0;
|
||||
bool lastButtonUpState = HIGH;
|
||||
bool lastButtonDownState = HIGH;
|
||||
// Flag to track if the waiting message for Jalur 2 has been sent
|
||||
bool waitingMessageSent = false;
|
||||
// Flag to track if the "Kereta telah lewat di Jalur 1!" message has been sent
|
||||
bool keretaLewatMessageSent = false;
|
||||
|
||||
int tresholdUltrasonik = 50; // Default 50 cm
|
||||
int tresholdPiezo = 300; // Default 300
|
||||
String phoneNumber = "6282221448622"; // Nomor telepon yang akan dihubungi
|
||||
String serviceURL = "http://192.168.37.201:3000/send-message"; // Default service URL
|
||||
|
||||
// Fungsi untuk mengambil status_kereta dari Firebase dan mengontrol palang
|
||||
void fetchStatusKereta() {
|
||||
// Coba ambil status kereta dari Firebase
|
||||
if (Firebase.RTDB.getBool(&fbdo, "/status_kereta")) {
|
||||
if (fbdo.dataType() == "boolean") { // Cek apakah tipe data adalah boolean
|
||||
bool statusKereta = fbdo.boolData(); // Ambil nilai boolean dari Firebase
|
||||
|
||||
// Hanya tampilkan status jika ada pembaruan
|
||||
static bool lastStatusKereta = false; // Variabel untuk menyimpan status terakhir
|
||||
if (statusKereta != lastStatusKereta) { // Cek apakah status berubah
|
||||
Serial.print("[INFO] Status kereta dari Firebase: ");
|
||||
Serial.println(statusKereta ? "DITUTUP" : "DIBUKA");
|
||||
lastStatusKereta = statusKereta; // Update status terakhir
|
||||
}
|
||||
|
||||
// Lakukan aksi berdasarkan status kereta
|
||||
if (statusKereta) {
|
||||
// Status kereta true, tutup palang
|
||||
servoJalur1.write(90); // Tutup palang
|
||||
digitalWrite(LED_BAHAYA, HIGH); // LED merah menyala
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH); // Bunyi buzzer
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("PALANG DITUTUP");
|
||||
} else {
|
||||
// Status kereta false, buka palang
|
||||
servoJalur1.write(0); // Buka palang
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW); // Matikan buzzer
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("PALANG DIBUKA");
|
||||
}
|
||||
} else {
|
||||
// Jika tipe data bukan boolean
|
||||
Serial.print("[ERROR] Data bukan boolean: ");
|
||||
Serial.println(fbdo.dataType()); // Tampilkan tipe data yang salah
|
||||
}
|
||||
} else {
|
||||
// Jika gagal mendapatkan data dari Firebase
|
||||
Serial.print("[ERROR] Gagal mendapatkan status kereta: ");
|
||||
Serial.println(fbdo.errorReason()); // Menampilkan alasan error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// === AMBIL DATA THRESHOLD DARI FIREBASE ===
|
||||
void updateThresholdFromFirebase() {
|
||||
if (Firebase.RTDB.getInt(&fbdo, "/treshold/ultrasonik") && fbdo.dataType() == "int") {
|
||||
tresholdUltrasonik = fbdo.intData();
|
||||
Serial.print("Treshold Ultrasonik diperbarui: ");
|
||||
Serial.println(tresholdUltrasonik);
|
||||
}
|
||||
|
||||
if (Firebase.RTDB.getInt(&fbdo, "/treshold/piezo") && fbdo.dataType() == "int") {
|
||||
tresholdPiezo = fbdo.intData();
|
||||
Serial.print("Treshold Piezo diperbarui: ");
|
||||
Serial.println(tresholdPiezo);
|
||||
}
|
||||
|
||||
if (Firebase.RTDB.getInt(&fbdo, "/treshold/interval_jeda") && fbdo.dataType() == "int") {
|
||||
intervalJeda = fbdo.intData() * 1000;
|
||||
Serial.print("Interval Jeda diperbarui: ");
|
||||
Serial.println(intervalJeda);
|
||||
}
|
||||
}
|
||||
|
||||
void sendWAAlert(String message) {
|
||||
HTTPClient http;
|
||||
http.begin(serviceURL); // Gunakan serviceURL yang telah disesuaikan
|
||||
|
||||
String payload = "{\"phone\": \"" + phoneNumber + "\", \"message\": \"" + message + "\"}"; // Gunakan phoneNumber langsung
|
||||
http.addHeader("Content-Type", "application/json");
|
||||
|
||||
// Kirim permintaan POST
|
||||
int httpResponseCode = http.POST(payload);
|
||||
|
||||
if (httpResponseCode > 0) {
|
||||
// Menyediakan feedback sukses
|
||||
Serial.println("Pesan WhatsApp terkirim ke " + phoneNumber + ": " + String(httpResponseCode));
|
||||
} else {
|
||||
// Menyediakan feedback gagal
|
||||
Serial.println("Gagal mengirim pesan WhatsApp ke " + phoneNumber + ": " + String(httpResponseCode));
|
||||
Serial.println("Error: " + http.errorToString(httpResponseCode));
|
||||
}
|
||||
|
||||
http.end(); // Tutup permintaan HTTP
|
||||
}
|
||||
|
||||
|
||||
// === SETUP ===
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); // komunikasi ke ESP1
|
||||
|
||||
servoJalur1.setPeriodHertz(50);
|
||||
servoJalur1.attach(SERVO_PIN);
|
||||
|
||||
Wire.begin(22, 21);
|
||||
lcd.init();
|
||||
lcd.backlight();
|
||||
|
||||
pinMode(TRIG1, OUTPUT);
|
||||
pinMode(ECHO1, INPUT);
|
||||
pinMode(TRIG2, OUTPUT);
|
||||
pinMode(ECHO2, INPUT);
|
||||
pinMode(PIEZO_PIN1, INPUT);
|
||||
pinMode(BUZZER_PIN, OUTPUT);
|
||||
pinMode(LED_AMAN, OUTPUT);
|
||||
pinMode(LED_BAHAYA, OUTPUT);
|
||||
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print("Menghubungkan...");
|
||||
Serial.println("Menghubungkan ke WiFi...");
|
||||
|
||||
// WiFiManager untuk konfigurasi URL
|
||||
WiFiManager wm;
|
||||
WiFiManagerParameter custom_service_url("service_url", "Service URL", serviceURL.c_str(), 40); // Ukuran maksimal 40 karakter
|
||||
wm.addParameter(&custom_service_url); // Menambahkan parameter
|
||||
|
||||
wm.setTimeout(60);
|
||||
if (!wm.autoConnect("PALANG 2-Setup")) {
|
||||
Serial.println("Gagal konek WiFi. Mode offline.");
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("Mode Offline");
|
||||
isOfflineMode = true; // Set mode offline
|
||||
delay(2000);
|
||||
} else {
|
||||
Serial.println("WiFi Terhubung!");
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("WiFi Terhubung");
|
||||
delay(2000);
|
||||
|
||||
// Ambil URL yang dimasukkan pengguna
|
||||
serviceURL = custom_service_url.getValue(); // Ambil URL yang dikonfigurasi
|
||||
Serial.println("Service URL: " + serviceURL); // Debug URL yang diambil
|
||||
|
||||
// Konfigurasi Firebase jika diperlukan
|
||||
config.api_key = API_KEY;
|
||||
config.database_url = DATABASE_URL;
|
||||
config.signer.tokens.legacy_token = LEGACY_TOKEN;
|
||||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
updateThresholdFromFirebase(); // Update threshold from Firebase
|
||||
}
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("PALANG PINTAR");
|
||||
Serial.println("Sistem Siap: PALANG PINTAR");
|
||||
}
|
||||
// Fungsi utama yang berjalan di loop
|
||||
void loop() {
|
||||
// Baca sensor Ultrasonik 1 untuk mendeteksi kereta
|
||||
digitalWrite(TRIG1, LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(TRIG1, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(TRIG1, LOW);
|
||||
long duration1 = pulseIn(ECHO1, HIGH);
|
||||
float distance1 = duration1 * 0.034 / 2; // Menghitung jarak
|
||||
|
||||
// Baca sensor Ultrasonik 2
|
||||
digitalWrite(TRIG2, LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(TRIG2, HIGH);
|
||||
delayMicroseconds(10);
|
||||
digitalWrite(TRIG2, LOW);
|
||||
long duration2 = pulseIn(ECHO2, HIGH);
|
||||
float distance2 = duration2 * 0.034 / 2; // Menghitung jarak
|
||||
|
||||
// Baca sensor Piezo
|
||||
int piezo1Val = analogRead(PIEZO_PIN1);
|
||||
|
||||
// Menampilkan status sensor ke Serial Monitor setiap interval tertentu
|
||||
if (millis() - lastSerialPrint >= interval) {
|
||||
lastSerialPrint = millis();
|
||||
Serial.println("===== STATUS SENSOR =====");
|
||||
Serial.print("Ultrasonik 1: "); Serial.println(distance1);
|
||||
Serial.print("Ultrasonik 2: "); Serial.println(distance2);
|
||||
Serial.print("Piezo1: "); Serial.println(piezo1Val);
|
||||
|
||||
// Jika nilai piezo 0, tampilkan status palang terbuka atau tidak ada kereta
|
||||
if (piezo1Val == 0) {
|
||||
Serial.println("[INFO] Palang terbuka - Tidak ada kereta");
|
||||
}
|
||||
}
|
||||
|
||||
// === Ambil Status Kereta secara Berkala dari Firebase ===
|
||||
fetchStatusKereta(); // Fungsi yang memeriksa status_kereta setiap interval dan mengontrol palang
|
||||
|
||||
// === Deteksi Kereta Masuk (Jalur 2) ===
|
||||
if (distance1 < tresholdUltrasonik && piezo1Val > tresholdPiezo && !keretaTerdeteksi) {
|
||||
// Periksa status_kereta di Firebase
|
||||
if (Firebase.RTDB.getBool(&fbdo, "/status_kereta")) {
|
||||
bool statusKereta = fbdo.boolData(); // status_kereta (perintah umum)
|
||||
|
||||
if (!statusKereta) { // Hanya tutup palang jika status_kereta adalah false
|
||||
digitalWrite(LED_BAHAYA, HIGH);
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH); // Bunyi buzzer
|
||||
servoJalur1.write(90); // Tutup palang Jalur 2
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("KERETA DATANG");
|
||||
sendWAAlert("Peringatan: Kereta datang di Jalur 2!"); // Kirim pesan WA
|
||||
Serial.println("[INFO] Kereta terdeteksi di Jalur 2 - Palang DITUTUP");
|
||||
|
||||
// Update status_kereta di Firebase
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta", true); // Update status kereta menjadi true
|
||||
|
||||
// Kirim perintah ke ESP Jalur 1 untuk tutup palang jika dalam mode offline
|
||||
if (isOfflineMode) {
|
||||
Serial2.write('0'); // Perintah tutup ke ESP Jalur 1
|
||||
}
|
||||
|
||||
// Update status_kereta_jalur2 di Firebase
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta_jalur2", true); // Update status Jalur 2
|
||||
|
||||
keretaTerdeteksi = true;
|
||||
keretaLewat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === Cek Kereta Lewat (Jalur 2) ===
|
||||
if (keretaTerdeteksi && distance2 < tresholdUltrasonik) {
|
||||
keretaLewat = true;
|
||||
}
|
||||
|
||||
if (keretaTerdeteksi && keretaLewat && distance2 > tresholdUltrasonik) {
|
||||
// Update status_kereta_jalur2 menjadi false setelah kereta lewat
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta_jalur2", false); // Status Jalur 2 menjadi false
|
||||
|
||||
// Kirim pesan "Kereta telah lewat di Jalur 2!" hanya sekali
|
||||
if (!keretaLewatMessageSent) {
|
||||
sendWAAlert("Peringatan: Kereta telah lewat di Jalur 2!"); // Kirim pesan WA
|
||||
keretaLewatMessageSent = true; // Set flag to prevent sending multiple messages
|
||||
Serial.println("[INFO] Kereta sudah lewat - Pesan telah dikirim.");
|
||||
}
|
||||
|
||||
// Periksa status_kereta_jalur1
|
||||
if (Firebase.RTDB.getBool(&fbdo, "/status_kereta_jalur1")) {
|
||||
bool statusKeretaJalur1 = fbdo.boolData(); // Cek status_kereta_jalur1
|
||||
|
||||
if (statusKeretaJalur1 && !waitingMessageSent) { // Jika status_kereta_jalur1 adalah true, kirim pesan menunggu
|
||||
sendWAAlert("Peringatan: Menunggu kereta 1 lewat!"); // Kirim pesan WA
|
||||
Serial.println("[INFO] Menunggu kereta 1 lewat...");
|
||||
waitingMessageSent = true; // Set flag to true to prevent multiple messages
|
||||
}
|
||||
|
||||
// Cek jika status_kereta adalah false dan status_kereta_jalur1 juga false
|
||||
if (!statusKeretaJalur1) {
|
||||
bool statusKereta = fbdo.boolData(); // Cek status_kereta global
|
||||
|
||||
if (!statusKereta) { // Hanya buka palang jika status_kereta adalah false
|
||||
servoJalur1.write(0); // Buka palang Jalur 2
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW); // Matikan buzzer
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("KERETA LEWAT");
|
||||
|
||||
Serial.println("[INFO] Kereta sudah lewat - Palang DIBUKA");
|
||||
|
||||
// Update status_kereta di Firebase
|
||||
Firebase.RTDB.setBool(&fbdo, "/status_kereta", false); // Update status kereta menjadi false
|
||||
|
||||
// Kirim perintah ke ESP Jalur 1 untuk membuka palang jika dalam mode offline
|
||||
if (isOfflineMode) {
|
||||
Serial2.write('1'); // Perintah buka ke ESP Jalur 1
|
||||
}
|
||||
|
||||
keretaTerdeteksi = false;
|
||||
keretaLewat = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === Terima sinyal dari ESP Jalur 1 === (Mode Offline)
|
||||
if (isOfflineMode && Serial2.available() > 0) {
|
||||
char incomingByte = Serial2.read();
|
||||
if (incomingByte == '0') { // Perintah tutup dari ESP Jalur 1
|
||||
servoJalur1.write(90); // Tutup palang
|
||||
digitalWrite(LED_BAHAYA, HIGH);
|
||||
digitalWrite(LED_AMAN, LOW);
|
||||
digitalWrite(BUZZER_PIN, HIGH); // Bunyi buzzer
|
||||
Serial.println("[ESP1] Sinyal diterima - Palang DITUTUP oleh ESP1");
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("ESP2: PALANG TUTUP");
|
||||
}
|
||||
if (incomingByte == '1') { // Perintah buka dari ESP Jalur 1
|
||||
servoJalur1.write(0); // Buka palang
|
||||
digitalWrite(LED_BAHAYA, LOW);
|
||||
digitalWrite(LED_AMAN, HIGH);
|
||||
digitalWrite(BUZZER_PIN, LOW);
|
||||
Serial.println("[ESP1] Sinyal diterima - Palang DIBUKA oleh ESP1");
|
||||
|
||||
lcd.clear(); lcd.setCursor(0, 0); lcd.print("ESP2: PALANG BUKA");
|
||||
}
|
||||
}
|
||||
|
||||
delay(500); // jeda agar loop tidak terlalu cepat
|
||||
}
|
Loading…
Reference in New Issue