add new fitur register cards and change configuration
This commit is contained in:
parent
837112d41e
commit
8e48853055
|
@ -0,0 +1,351 @@
|
|||
#include <Wire.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <FirebaseESP8266.h>
|
||||
#include <DHT.h>
|
||||
|
||||
// Konfigurasi WiFi
|
||||
#define WIFI_SSID "smartcab"
|
||||
#define WIFI_PASSWORD "123123123"
|
||||
|
||||
// Konfigurasi Firebase
|
||||
#define FIREBASE_HOST "smartcab-8bb42-default-rtdb.firebaseio.com"
|
||||
#define FIREBASE_AUTH "kiiQoFa6Ckp7bL2oRLbaTSGQth9z0PgN64Ybv8dw"
|
||||
|
||||
FirebaseData firebaseData;
|
||||
FirebaseConfig firebaseConfig;
|
||||
FirebaseAuth firebaseAuth;
|
||||
|
||||
// MPU6050 I2C address
|
||||
#define MPU6050_ADDR 0x68
|
||||
|
||||
const int relayMPUPin = D6; // Relay untuk MPU6050
|
||||
const int relayKipasPin = D5; // Relay untuk kipas
|
||||
const int dhtPin = D3; // DHT11 sensor
|
||||
#define DHTTYPE DHT11
|
||||
DHT dht(dhtPin, DHTTYPE);
|
||||
|
||||
float threshold = 0.05;
|
||||
float baseAccelX, baseAccelY, baseAccelZ;
|
||||
bool relayActive = false;
|
||||
bool mpuEnabled = true;
|
||||
unsigned long relayStartTime = 0;
|
||||
unsigned long lastUpdateTime = 0;
|
||||
unsigned long lastI2CCheckTime = 0;
|
||||
const unsigned long restartInterval = 6 * 60 * 60 * 1000; // Restart otomatis 6 jam
|
||||
unsigned long firebaseRetryCount = 0; // Menghitung percobaan koneksi ke Firebase
|
||||
|
||||
// Tambahkan variabel global untuk timestamp
|
||||
unsigned long lastHeartbeatTime = 0;
|
||||
const unsigned long heartbeatInterval = 60000; // 60 detik = 1 menit
|
||||
unsigned long lastFirebaseRetryTime = 0;
|
||||
const unsigned long firebaseRetryInterval = 5000; // 5 detik antara percobaan
|
||||
|
||||
// Fungsi untuk membaca data dari MPU6050
|
||||
void readMPU6050(int16_t* ax, int16_t* ay, int16_t* az) {
|
||||
Wire.beginTransmission(MPU6050_ADDR);
|
||||
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
|
||||
Wire.endTransmission(false);
|
||||
Wire.requestFrom(MPU6050_ADDR, 6, true); // request a total of 6 registers
|
||||
|
||||
*ax = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
|
||||
*ay = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
|
||||
*az = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
|
||||
}
|
||||
|
||||
// Fungsi untuk menginisialisasi MPU6050
|
||||
bool initMPU6050() {
|
||||
Wire.beginTransmission(MPU6050_ADDR);
|
||||
Wire.write(0x6B); // PWR_MGMT_1 register
|
||||
Wire.write(0); // set to zero (wakes up the MPU-6050)
|
||||
return Wire.endTransmission(true) == 0;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin(D2, D1); // SDA = D2, SCL = D1
|
||||
|
||||
// Tambahkan pinMode untuk relay
|
||||
pinMode(relayMPUPin, OUTPUT);
|
||||
pinMode(relayKipasPin, OUTPUT);
|
||||
|
||||
// Matikan semua relay saat startup
|
||||
digitalWrite(relayMPUPin, HIGH); // Relay MPU OFF
|
||||
digitalWrite(relayKipasPin, HIGH); // Relay Kipas OFF
|
||||
|
||||
// Koneksi ke WiFi dulu
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
Serial.print("Menghubungkan ke WiFi");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
Serial.println("\nTerhubung ke WiFi");
|
||||
|
||||
// Konfigurasi Firebase
|
||||
firebaseConfig.host = FIREBASE_HOST;
|
||||
firebaseConfig.signer.tokens.legacy_token = FIREBASE_AUTH;
|
||||
|
||||
Firebase.begin(&firebaseConfig, &firebaseAuth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
|
||||
bool firebaseConnected = false;
|
||||
for (int i = 0; i < 3; i++) { // Coba 3 kali
|
||||
if (Firebase.setString(firebaseData, "/logs/systemESP", "Device online")) {
|
||||
firebaseConnected = true;
|
||||
Serial.println("Firebase terhubung");
|
||||
break;
|
||||
} else {
|
||||
Serial.println("Gagal menghubungkan ke Firebase, mencoba lagi...");
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!firebaseConnected) {
|
||||
Serial.println("Tidak dapat terhubung ke Firebase. Sistem keamanan dimatikan.");
|
||||
mpuEnabled = false; // Matikan keamanan jika Firebase tidak terhubung
|
||||
}
|
||||
|
||||
// Inisialisasi sensor
|
||||
if (!initMPU6050()) {
|
||||
Serial.println("MPU6050 tidak terhubung!");
|
||||
if (firebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "disconnected");
|
||||
}
|
||||
mpuEnabled = false;
|
||||
} else {
|
||||
if (firebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "connected");
|
||||
}
|
||||
calibrateSensor();
|
||||
}
|
||||
|
||||
dht.begin();
|
||||
|
||||
// Cek DHT11
|
||||
float testReading = dht.readTemperature();
|
||||
if (isnan(testReading)) {
|
||||
Serial.println("DHT11 tidak terhubung atau error!");
|
||||
if (firebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "disconnected");
|
||||
}
|
||||
} else {
|
||||
if (firebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "connected");
|
||||
}
|
||||
}
|
||||
|
||||
// Konfigurasi NTP
|
||||
configTime(7 * 3600, 0, "pool.ntp.org");
|
||||
Serial.println("Waiting for time sync");
|
||||
while (time(nullptr) < 1000000000) {
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
Serial.println("\nTime synchronized");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Cek koneksi WiFi
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.println("WiFi terputus, mencoba menyambung kembali...");
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
delay(5000); // Tunggu 5 detik
|
||||
|
||||
// Jika masih tidak terhubung, matikan keamanan
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
mpuEnabled = false;
|
||||
digitalWrite(relayMPUPin, HIGH); // Pastikan relay OFF
|
||||
}
|
||||
return; // Keluar dari loop dan coba lagi
|
||||
}
|
||||
|
||||
// Update lastActive dengan unix timestamp
|
||||
if (millis() - lastHeartbeatTime >= heartbeatInterval) {
|
||||
lastHeartbeatTime = millis();
|
||||
unsigned long epochTime = time(nullptr);
|
||||
bool heartbeatSent = false;
|
||||
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActive", epochTime)) {
|
||||
Serial.println("Heartbeat sent: " + String(epochTime));
|
||||
// Tambahkan update status Device online saat heartbeat berhasil
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device online");
|
||||
Serial.println("Device status updated: Online");
|
||||
heartbeatSent = true;
|
||||
firebaseRetryCount = 0; // Reset counter jika berhasil
|
||||
} else {
|
||||
Serial.println("Failed to send heartbeat: " + firebaseData.errorReason());
|
||||
// Jika gagal mengirim heartbeat, set status offline
|
||||
firebaseRetryCount++;
|
||||
|
||||
if (firebaseRetryCount >= 3) { // Setelah 3 kali gagal
|
||||
Serial.println("Firebase tidak dapat diakses setelah beberapa percobaan, mematikan sistem keamanan");
|
||||
mpuEnabled = false; // Matikan keamanan
|
||||
digitalWrite(relayMPUPin, HIGH); // Pastikan relay OFF
|
||||
Firebase.setString(firebaseData, "/security/status", "off"); // Coba set status off
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device offline");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cek jika tidak ada perubahan dalam 70 detik
|
||||
if (millis() - lastHeartbeatTime > 70000) {
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device offline");
|
||||
}
|
||||
|
||||
// Tambahkan pengecekan status restart di awal loop
|
||||
if (Firebase.getString(firebaseData, "/control/restartESP")) {
|
||||
String restartStatus = firebaseData.stringData();
|
||||
if (restartStatus == "true") {
|
||||
Serial.println("Perintah restart diterima dari Firebase");
|
||||
// Reset status restart di Firebase ke false
|
||||
Firebase.setString(firebaseData, "/control/restartESP", "false");
|
||||
// Kirim log sebelum restart
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device restarting by command...");
|
||||
delay(1000); // Tunggu sebentar agar data terkirim
|
||||
ESP.restart();
|
||||
}
|
||||
} else {
|
||||
Serial.println("Gagal membaca status restart: " + firebaseData.errorReason());
|
||||
// Jika gagal membaca dari Firebase, tambahkan counter
|
||||
firebaseRetryCount++;
|
||||
|
||||
if (firebaseRetryCount >= 3) { // Setelah 3 kali gagal
|
||||
Serial.println("Tidak dapat mengakses Firebase, mematikan sistem keamanan");
|
||||
mpuEnabled = false; // Matikan keamanan
|
||||
digitalWrite(relayMPUPin, HIGH); // Pastikan relay OFF
|
||||
// Masih coba set status meski kemungkinan gagal
|
||||
Firebase.setString(firebaseData, "/security/status", "off");
|
||||
}
|
||||
}
|
||||
|
||||
// Cek auto-restart berdasarkan interval
|
||||
if (millis() > restartInterval) {
|
||||
Serial.println("Auto-restart setelah " + String(restartInterval/3600000) + " jam");
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device auto-restarting...");
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
// **Cek status MPU6050 setiap 30 detik**
|
||||
if (millis() - lastI2CCheckTime >= 30000) {
|
||||
lastI2CCheckTime = millis();
|
||||
if (!initMPU6050()) {
|
||||
Serial.println("MPU6050 tidak merespons! Reset I2C...");
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "error");
|
||||
|
||||
Wire.begin(D2, D1);
|
||||
if (initMPU6050()) {
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **Baca status MPU dari Firebase**
|
||||
bool readSuccess = false;
|
||||
if (Firebase.getString(firebaseData, "/security/status")) {
|
||||
String mpuStatus = firebaseData.stringData();
|
||||
Serial.print("Status MPU dari Firebase: ");
|
||||
Serial.println(mpuStatus);
|
||||
mpuEnabled = (mpuStatus == "on");
|
||||
readSuccess = true;
|
||||
firebaseRetryCount = 0; // Reset counter jika berhasil
|
||||
} else {
|
||||
Serial.println("Gagal membaca data dari Firebase: " + firebaseData.errorReason());
|
||||
Firebase.setString(firebaseData, "/logs/error", firebaseData.errorReason());
|
||||
|
||||
// Jika gagal memperoleh data dari Firebase, tambahkan counter
|
||||
firebaseRetryCount++;
|
||||
|
||||
if (firebaseRetryCount >= 3) { // Setelah 3 kali gagal
|
||||
// Cek jika waktu cukup berlalu untuk percobaan berikutnya
|
||||
if (millis() - lastFirebaseRetryTime >= firebaseRetryInterval) {
|
||||
lastFirebaseRetryTime = millis();
|
||||
|
||||
Serial.println("Tidak dapat membaca status dari Firebase, mematikan sistem keamanan");
|
||||
mpuEnabled = false; // Matikan keamanan
|
||||
digitalWrite(relayMPUPin, HIGH); // Pastikan relay OFF
|
||||
|
||||
// Masih coba set status meski kemungkinan gagal
|
||||
Firebase.setString(firebaseData, "/security/status", "off");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **Proses MPU6050**
|
||||
if (mpuEnabled) {
|
||||
if (millis() - lastUpdateTime >= 10) {
|
||||
lastUpdateTime = millis();
|
||||
|
||||
int16_t ax, ay, az;
|
||||
readMPU6050(&ax, &ay, &az);
|
||||
|
||||
float accelX = ax / 16384.0;
|
||||
float accelY = ay / 16384.0;
|
||||
float accelZ = az / 16384.0;
|
||||
|
||||
float deltaAccel = sqrt(pow(accelX - baseAccelX, 2) + pow(accelY - baseAccelY, 2) + pow(accelZ - baseAccelZ, 2));
|
||||
|
||||
if (deltaAccel > threshold && !relayActive) {
|
||||
Serial.println("Getaran terdeteksi! Relay ON.");
|
||||
digitalWrite(relayMPUPin, LOW);
|
||||
relayActive = true;
|
||||
relayStartTime = millis();
|
||||
Firebase.setString(firebaseData, "/security/motion", "detected");
|
||||
}
|
||||
|
||||
if (relayActive && millis() - relayStartTime >= 8000) {
|
||||
Serial.println("Relay mati, kalibrasi ulang.");
|
||||
digitalWrite(relayMPUPin, HIGH);
|
||||
relayActive = false;
|
||||
calibrateSensor();
|
||||
Firebase.setString(firebaseData, "/security/motion", "clear");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
digitalWrite(relayMPUPin, HIGH); // Pastikan relay OFF saat disabled
|
||||
relayActive = false;
|
||||
Firebase.setString(firebaseData, "/security/motion", "disabled");
|
||||
}
|
||||
|
||||
// **Baca suhu dan kelembaban dari DHT11**
|
||||
float suhu = dht.readTemperature();
|
||||
float humidity = dht.readHumidity();
|
||||
|
||||
if (isnan(suhu) || isnan(humidity)) {
|
||||
Serial.println("Gagal membaca data dari DHT11!");
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "error");
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "connected");
|
||||
|
||||
Serial.print("Suhu: ");
|
||||
Serial.print(suhu);
|
||||
Serial.println(" °C");
|
||||
Serial.print("Kelembaban: ");
|
||||
Serial.print(humidity);
|
||||
Serial.println(" %");
|
||||
|
||||
Firebase.setFloat(firebaseData, "/dht11/temperature", suhu);
|
||||
Firebase.setFloat(firebaseData, "/dht11/humidity", humidity);
|
||||
}
|
||||
|
||||
// **Kendalikan relay kipas**
|
||||
if (suhu > 40) {
|
||||
Serial.println("Suhu tinggi! Kipas ON.");
|
||||
digitalWrite(relayKipasPin, LOW);
|
||||
Firebase.setString(firebaseData, "/security/fan", "ON");
|
||||
} else {
|
||||
digitalWrite(relayKipasPin, HIGH);
|
||||
Firebase.setString(firebaseData, "/security/fan", "OFF");
|
||||
}
|
||||
|
||||
yield();
|
||||
}
|
||||
|
||||
void calibrateSensor() {
|
||||
int16_t ax, ay, az;
|
||||
readMPU6050(&ax, &ay, &az);
|
||||
baseAccelX = ax / 16384.0;
|
||||
baseAccelY = ay / 16384.0;
|
||||
baseAccelZ = az / 16384.0;
|
||||
Serial.println("Kalibrasi selesai!");
|
||||
}
|
|
@ -36,6 +36,10 @@ const unsigned long restartInterval = 6 * 60 * 60 * 1000; // Restart otomatis 6
|
|||
unsigned long lastHeartbeatTime = 0;
|
||||
const unsigned long heartbeatInterval = 60000; // 60 detik = 1 menit
|
||||
|
||||
// Tambahkan variabel untuk pengecekan koneksi WiFi
|
||||
unsigned long lastWiFiCheckTime = 0;
|
||||
const unsigned long wifiCheckInterval = 10000; // 10 detik
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Wire.begin(D2, D1); // SDA = D2, SCL = D1
|
||||
|
@ -105,29 +109,67 @@ void setup() {
|
|||
}
|
||||
|
||||
void loop() {
|
||||
// Periksa koneksi WiFi dan Firebase
|
||||
if (millis() - lastWiFiCheckTime >= wifiCheckInterval) {
|
||||
lastWiFiCheckTime = millis();
|
||||
|
||||
// Cek koneksi WiFi
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.println("WiFi terputus! Security dinonaktifkan.");
|
||||
mpuEnabled = false;
|
||||
digitalWrite(relayMPUPin, HIGH); // Matikan relay MPU
|
||||
relayActive = false;
|
||||
|
||||
// Coba hubungkan kembali
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
// Update lastActive dengan unix timestamp
|
||||
if (millis() - lastHeartbeatTime >= heartbeatInterval) {
|
||||
lastHeartbeatTime = millis();
|
||||
unsigned long epochTime = time(nullptr);
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActive", epochTime)) {
|
||||
Serial.println("Heartbeat sent: " + String(epochTime));
|
||||
// Tambahkan update status Device online saat heartbeat berhasil
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device online");
|
||||
Serial.println("Device status updated: Online");
|
||||
|
||||
// Cek apakah terhubung ke WiFi
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
unsigned long epochTime = time(nullptr);
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActive", epochTime)) {
|
||||
Serial.println("Heartbeat sent: " + String(epochTime));
|
||||
// Tambahkan update status Device online saat heartbeat berhasil
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device online");
|
||||
Serial.println("Device status updated: Online");
|
||||
} else {
|
||||
Serial.println("Failed to send heartbeat");
|
||||
// Jika gagal mengirim heartbeat, set status offline
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device offline");
|
||||
// Matikan security karena Firebase tidak dapat diakses
|
||||
mpuEnabled = false;
|
||||
digitalWrite(relayMPUPin, HIGH);
|
||||
relayActive = false;
|
||||
Serial.println("Firebase tidak dapat diakses! Security dinonaktifkan.");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Failed to send heartbeat");
|
||||
// Jika gagal mengirim heartbeat, set status offline
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device offline");
|
||||
Serial.println("WiFi terputus! Tidak dapat mengirim heartbeat.");
|
||||
// Pastikan security mati ketika WiFi terputus
|
||||
mpuEnabled = false;
|
||||
digitalWrite(relayMPUPin, HIGH);
|
||||
relayActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Cek jika tidak ada perubahan dalam 70 detik
|
||||
if (millis() - lastHeartbeatTime > 70000) {
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device offline");
|
||||
// WiFi atau Firebase bermasalah, set security off
|
||||
mpuEnabled = false;
|
||||
digitalWrite(relayMPUPin, HIGH);
|
||||
relayActive = false;
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device offline");
|
||||
}
|
||||
}
|
||||
|
||||
// Tambahkan pengecekan status restart di awal loop
|
||||
if (Firebase.getString(firebaseData, "/control/restartESP")) {
|
||||
if (WiFi.status() == WL_CONNECTED && Firebase.getString(firebaseData, "/control/restartESP")) {
|
||||
String restartStatus = firebaseData.stringData();
|
||||
if (restartStatus == "true") {
|
||||
Serial.println("Perintah restart diterima dari Firebase");
|
||||
|
@ -143,8 +185,10 @@ void loop() {
|
|||
// Cek auto-restart berdasarkan interval
|
||||
if (millis() > restartInterval) {
|
||||
Serial.println("Auto-restart setelah " + String(restartInterval/3600000) + " jam");
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device auto-restarting...");
|
||||
delay(1000);
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/systemESP", "Device auto-restarting...");
|
||||
delay(1000);
|
||||
}
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
|
@ -153,26 +197,42 @@ void loop() {
|
|||
lastI2CCheckTime = millis();
|
||||
if (!mpu.testConnection()) {
|
||||
Serial.println("MPU6050 tidak merespons! Reset I2C...");
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "error");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "error");
|
||||
}
|
||||
|
||||
Wire.begin(D2, D1);
|
||||
mpu.initialize();
|
||||
|
||||
if (mpu.testConnection()) {
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "connected");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/mpu/status", "connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **Baca status MPU dari Firebase**
|
||||
if (Firebase.getString(firebaseData, "/security/status")) {
|
||||
String mpuStatus = firebaseData.stringData();
|
||||
Serial.print("Status MPU dari Firebase: ");
|
||||
Serial.println(mpuStatus);
|
||||
mpuEnabled = (mpuStatus == "on");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (Firebase.getString(firebaseData, "/security/status")) {
|
||||
String mpuStatus = firebaseData.stringData();
|
||||
Serial.print("Status MPU dari Firebase: ");
|
||||
Serial.println(mpuStatus);
|
||||
mpuEnabled = (mpuStatus == "on");
|
||||
} else {
|
||||
Serial.println("Gagal membaca data dari Firebase!");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/error", firebaseData.errorReason());
|
||||
}
|
||||
// Matikan security karena Firebase tidak dapat diakses
|
||||
mpuEnabled = false;
|
||||
digitalWrite(relayMPUPin, HIGH);
|
||||
relayActive = false;
|
||||
Serial.println("Firebase tidak dapat diakses! Security dinonaktifkan.");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Gagal membaca data dari Firebase!");
|
||||
Firebase.setString(firebaseData, "/logs/error", firebaseData.errorReason());
|
||||
// Pastikan security mati ketika WiFi terputus
|
||||
mpuEnabled = false;
|
||||
}
|
||||
|
||||
// **Proses MPU6050**
|
||||
|
@ -194,7 +254,9 @@ void loop() {
|
|||
digitalWrite(relayMPUPin, LOW);
|
||||
relayActive = true;
|
||||
relayStartTime = millis();
|
||||
Firebase.setString(firebaseData, "/security/motion", "detected");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/security/motion", "detected");
|
||||
}
|
||||
}
|
||||
|
||||
if (relayActive && millis() - relayStartTime >= 8000) {
|
||||
|
@ -202,13 +264,17 @@ void loop() {
|
|||
digitalWrite(relayMPUPin, HIGH);
|
||||
relayActive = false;
|
||||
calibrateSensor();
|
||||
Firebase.setString(firebaseData, "/security/motion", "clear");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/security/motion", "clear");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
digitalWrite(relayMPUPin, HIGH); // Pastikan relay OFF saat disabled
|
||||
relayActive = false;
|
||||
Firebase.setString(firebaseData, "/security/motion", "disabled");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/security/motion", "disabled");
|
||||
}
|
||||
}
|
||||
|
||||
// **Baca suhu dan kelembaban dari DHT11**
|
||||
|
@ -217,9 +283,16 @@ void loop() {
|
|||
|
||||
if (isnan(suhu) || isnan(humidity)) {
|
||||
Serial.println("Gagal membaca data dari DHT11!");
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "error");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "error");
|
||||
}
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "connected");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/logs/dht/status", "connected");
|
||||
|
||||
Firebase.setFloat(firebaseData, "/dht11/temperature", suhu);
|
||||
Firebase.setFloat(firebaseData, "/dht11/humidity", humidity);
|
||||
}
|
||||
|
||||
Serial.print("Suhu: ");
|
||||
Serial.print(suhu);
|
||||
|
@ -227,19 +300,20 @@ void loop() {
|
|||
Serial.print("Kelembaban: ");
|
||||
Serial.print(humidity);
|
||||
Serial.println(" %");
|
||||
|
||||
Firebase.setFloat(firebaseData, "/dht11/temperature", suhu);
|
||||
Firebase.setFloat(firebaseData, "/dht11/humidity", humidity);
|
||||
}
|
||||
|
||||
// **Kendalikan relay kipas**
|
||||
if (suhu > 40) {
|
||||
Serial.println("Suhu tinggi! Kipas ON.");
|
||||
digitalWrite(relayKipasPin, LOW);
|
||||
Firebase.setString(firebaseData, "/security/fan", "ON");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/security/fan", "ON");
|
||||
}
|
||||
} else {
|
||||
digitalWrite(relayKipasPin, HIGH);
|
||||
Firebase.setString(firebaseData, "/security/fan", "OFF");
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Firebase.setString(firebaseData, "/security/fan", "OFF");
|
||||
}
|
||||
}
|
||||
|
||||
yield();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <SPI.h>
|
||||
#include <MFRC522.h>
|
||||
#include <Servo.h>
|
||||
#include <time.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
// WiFi Credentials
|
||||
#define WIFI_SSID "smartcab"
|
||||
|
@ -26,87 +26,182 @@ MFRC522 mfrc522(SS_PIN, RST_PIN);
|
|||
Servo myServo;
|
||||
#define SERVO_PIN D2 // Pin servo
|
||||
|
||||
// **ID kartu yang diizinkan**
|
||||
String kartuTerdaftar[] = {"53ed8434", "3b4f7d9e", "5b85e19d", "cb31e19f", "5b58179f", "1b22e9f"};
|
||||
bool servoTerbuka = false; // Status awal servo (tertutup)
|
||||
// EEPROM Configuration
|
||||
#define EEPROM_SIZE 512
|
||||
#define MAX_CARDS 20
|
||||
#define CARD_SIZE 8 // 8 bytes per card (4 byte UID in hex = 8 chars)
|
||||
#define EEPROM_SIGNATURE 0xAA // Signature byte to check if EEPROM is initialized
|
||||
|
||||
// Tambahkan variabel global untuk last active
|
||||
// Status variables
|
||||
bool servoTerbuka = false; // Status awal servo (tertutup)
|
||||
unsigned long previousMillis = 0;
|
||||
const long interval = 60000; // interval 1 menit dalam milliseconds
|
||||
|
||||
// Tambahkan di bagian global variables
|
||||
unsigned long lastHeartbeatTime = 0;
|
||||
const long heartbeatInterval = 60000; // 1 menit dalam milliseconds
|
||||
unsigned long lastCommandCheck = 0;
|
||||
const long commandCheckInterval = 1000; // 1 detik interval untuk cek command
|
||||
unsigned long bootTime = 0; // Waktu saat device booting
|
||||
unsigned long lastWiFiCheck = 0; // Waktu terakhir cek WiFi
|
||||
const long wifiCheckInterval = 5000; // Interval cek koneksi WiFi (5 detik)
|
||||
|
||||
// Flag untuk status koneksi
|
||||
bool isWiFiConnected = false;
|
||||
bool isFirebaseConnected = false;
|
||||
|
||||
// Flag untuk indikasi ada command baru dari Firebase
|
||||
bool pendingCommand = false;
|
||||
String currentCommand = "";
|
||||
String currentCardId = "";
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("\n=== Smart Cabinet System Starting ===");
|
||||
|
||||
// Koneksi ke WiFi
|
||||
// Catat waktu boot untuk referensi waktu lokal
|
||||
bootTime = millis();
|
||||
|
||||
// Initialize EEPROM
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
initializeEEPROM();
|
||||
|
||||
// Mulai koneksi WiFi (non-blocking)
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
Serial.print("Menghubungkan ke WiFi");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(500);
|
||||
}
|
||||
Serial.println("\nWiFi Terhubung!");
|
||||
|
||||
// Konfigurasi Firebase
|
||||
config.host = FIREBASE_HOST;
|
||||
config.signer.tokens.legacy_token = FIREBASE_AUTH;
|
||||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
|
||||
// Konfigurasi NTP dan tunggu sinkronisasi
|
||||
configTime(7 * 3600, 0, "pool.ntp.org"); // GMT+7
|
||||
Serial.println("Menunggu sinkronisasi waktu");
|
||||
while (time(nullptr) < 1000000000) {
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
Serial.println("\nWaktu tersinkronisasi!");
|
||||
|
||||
// Setelah waktu tersinkronisasi, baru kirim timestamp pertama
|
||||
unsigned long epochTime = time(nullptr);
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActiveWemos", epochTime)) {
|
||||
Serial.println("Initial timestamp sent: " + String(epochTime));
|
||||
} else {
|
||||
Serial.println("Failed to send initial timestamp");
|
||||
}
|
||||
|
||||
Serial.println("Memulai koneksi WiFi di background...");
|
||||
|
||||
// Inisialisasi RFID
|
||||
SPI.begin();
|
||||
mfrc522.PCD_Init();
|
||||
|
||||
// Cek koneksi RFID dengan cara yang lebih aman
|
||||
// Cek koneksi RFID
|
||||
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
|
||||
if (v == 0x00 || v == 0xFF) {
|
||||
Firebase.setString(firebaseData, "/logs/RFID/status", "Disconnected");
|
||||
Serial.println("RFID Connection Failed!");
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/logs/RFID/status", "Connected");
|
||||
Serial.println("RFID Connected!");
|
||||
}
|
||||
|
||||
// Inisialisasi Servo
|
||||
myServo.attach(SERVO_PIN, 500, 2500);
|
||||
if (myServo.attached()) {
|
||||
Firebase.setString(firebaseData, "/logs/servo/status", "Connected");
|
||||
Serial.println("Servo Connected!");
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/logs/servo/status", "Disconnected");
|
||||
Serial.println("Servo Connection Failed!");
|
||||
}
|
||||
myServo.write(0);
|
||||
|
||||
// Update path untuk restart control
|
||||
Firebase.setBool(firebaseData, "/control/restartWemos", false);
|
||||
|
||||
// Update status device saat startup
|
||||
Firebase.setString(firebaseData, "/logs/systemWemos", "Device Online");
|
||||
Serial.println("Setup selesai. Sistem berjalan...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Update path untuk pengecekan restart
|
||||
// Cek dan update status koneksi WiFi
|
||||
if (millis() - lastWiFiCheck >= wifiCheckInterval) {
|
||||
lastWiFiCheck = millis();
|
||||
checkWiFiConnection();
|
||||
}
|
||||
|
||||
// Cek apakah kartu RFID terdeteksi - selalu berjalan terlepas dari WiFi
|
||||
checkRFID();
|
||||
|
||||
// Fungsi-fungsi yang membutuhkan koneksi WiFi
|
||||
if (isWiFiConnected) {
|
||||
// Cek perintah restart
|
||||
checkRestartCommand();
|
||||
|
||||
// Cek perintah dari Firebase dengan interval untuk menghindari blocking
|
||||
if (millis() - lastCommandCheck >= commandCheckInterval) {
|
||||
lastCommandCheck = millis();
|
||||
checkFirebaseCommands();
|
||||
}
|
||||
|
||||
// Update status perangkat secara berkala
|
||||
updateDeviceStatus();
|
||||
|
||||
// Heartbeat ke Firebase
|
||||
sendHeartbeat();
|
||||
}
|
||||
|
||||
delay(100); // Kurangi delay untuk respon lebih cepat
|
||||
}
|
||||
|
||||
// Fungsi untuk mengecek dan memperbarui status koneksi WiFi
|
||||
void checkWiFiConnection() {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (!isWiFiConnected) {
|
||||
isWiFiConnected = true;
|
||||
Serial.println("WiFi terhubung!");
|
||||
Serial.print("IP Address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
// Setup Firebase saat WiFi baru terhubung
|
||||
setupFirebase();
|
||||
}
|
||||
} else {
|
||||
if (isWiFiConnected) {
|
||||
isWiFiConnected = false;
|
||||
isFirebaseConnected = false;
|
||||
Serial.println("WiFi terputus!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Firebase setelah WiFi terhubung
|
||||
void setupFirebase() {
|
||||
config.host = FIREBASE_HOST;
|
||||
config.signer.tokens.legacy_token = FIREBASE_AUTH;
|
||||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
|
||||
// Cek koneksi Firebase
|
||||
if (Firebase.ready()) {
|
||||
isFirebaseConnected = true;
|
||||
Serial.println("Firebase terhubung!");
|
||||
|
||||
// Kirim timestamp lokal ke Firebase
|
||||
unsigned long localTime = millis();
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActiveWemos", localTime)) {
|
||||
Serial.println("Initial timestamp sent: " + String(localTime));
|
||||
} else {
|
||||
Serial.println("Failed to send initial timestamp");
|
||||
}
|
||||
|
||||
// Update status device saat terhubung
|
||||
Firebase.setString(firebaseData, "/logs/systemWemos", "Device Online");
|
||||
|
||||
// Setup struktur data kartu di Firebase
|
||||
Firebase.setString(firebaseData, "/registered_cards/card", "");
|
||||
Firebase.setString(firebaseData, "/registered_cards/delete", "");
|
||||
Firebase.setString(firebaseData, "/registered_cards/status", "System connected");
|
||||
|
||||
// Update status peripheral
|
||||
updatePeripheralStatus();
|
||||
|
||||
// Upload daftar kartu ke Firebase
|
||||
uploadCardListToFirebase();
|
||||
} else {
|
||||
Serial.println("Gagal terhubung ke Firebase!");
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi untuk update status peripheral
|
||||
void updatePeripheralStatus() {
|
||||
// Cek status RFID
|
||||
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
|
||||
if (v == 0x00 || v == 0xFF) {
|
||||
Firebase.setString(firebaseData, "/logs/RFID/status", "Disconnected");
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/logs/RFID/status", "Connected");
|
||||
}
|
||||
|
||||
// Cek status Servo
|
||||
if (myServo.attached()) {
|
||||
Firebase.setString(firebaseData, "/logs/servo/status", "Connected");
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/logs/servo/status", "Disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi untuk cek perintah restart
|
||||
void checkRestartCommand() {
|
||||
if (Firebase.getBool(firebaseData, "/control/restartWemos")) {
|
||||
if (firebaseData.boolData() == true) {
|
||||
// Update status sebelum restart
|
||||
|
@ -116,8 +211,78 @@ void loop() {
|
|||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cek status RFID secara periodik dengan cara yang lebih aman
|
||||
// Fungsi untuk cek RFID
|
||||
void checkRFID() {
|
||||
// Cek apakah kartu RFID terdeteksi
|
||||
if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
|
||||
Serial.println("Kartu Terdeteksi!");
|
||||
|
||||
// Membaca UID kartu
|
||||
String rfidUID = "";
|
||||
for (byte i = 0; i < mfrc522.uid.size; i++) {
|
||||
rfidUID += String(mfrc522.uid.uidByte[i], HEX);
|
||||
}
|
||||
|
||||
Serial.print("UID: ");
|
||||
Serial.println(rfidUID);
|
||||
|
||||
// Cek apakah kartu terdaftar dalam EEPROM
|
||||
bool isCardRegistered = isCardInEEPROM(rfidUID);
|
||||
|
||||
if (isCardRegistered) {
|
||||
Serial.println("Kartu Terdaftar!");
|
||||
|
||||
if (!servoTerbuka) {
|
||||
Serial.println("Membuka kunci...");
|
||||
myServo.write(180);
|
||||
servoTerbuka = true;
|
||||
|
||||
// Update Firebase hanya jika terhubung
|
||||
if (isWiFiConnected && isFirebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/smartcab/servo_status", "Terbuka");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Mengunci kunci...");
|
||||
myServo.write(0);
|
||||
servoTerbuka = false;
|
||||
|
||||
// Update Firebase hanya jika terhubung
|
||||
if (isWiFiConnected && isFirebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/smartcab/servo_status", "Terkunci");
|
||||
}
|
||||
}
|
||||
|
||||
// Kirim status ke Firebase jika terhubung
|
||||
if (isWiFiConnected && isFirebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/smartcab/last_access", "Terdaftar");
|
||||
Firebase.setString(firebaseData, "/smartcab/status_device", rfidUID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.println("Kartu Tidak Terdaftar! Mengunci servo...");
|
||||
|
||||
// Paksa servo terkunci jika kartu tidak dikenal
|
||||
myServo.write(0);
|
||||
servoTerbuka = false;
|
||||
|
||||
// Update Firebase hanya jika terhubung
|
||||
if (isWiFiConnected && isFirebaseConnected) {
|
||||
Firebase.setString(firebaseData, "/smartcab/servo_status", "Terkunci");
|
||||
Firebase.setString(firebaseData, "/smartcab/last_access", "Tidak Terdaftar");
|
||||
Firebase.setString(firebaseData, "/smartcab/status_device", rfidUID);
|
||||
}
|
||||
}
|
||||
|
||||
mfrc522.PICC_HaltA(); // Hentikan komunikasi RFID
|
||||
mfrc522.PCD_StopCrypto1();
|
||||
}
|
||||
}
|
||||
|
||||
// Update status perangkat
|
||||
void updateDeviceStatus() {
|
||||
// Cek status RFID secara periodik
|
||||
byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
|
||||
if (v == 0x00 || v == 0xFF) {
|
||||
if (Firebase.getString(firebaseData, "/logs/RFID/status") &&
|
||||
|
@ -138,13 +303,16 @@ void loop() {
|
|||
Firebase.setString(firebaseData, "/logs/servo/status", "Disconnected");
|
||||
Serial.println("Servo Disconnected!");
|
||||
}
|
||||
}
|
||||
|
||||
// Update lastActive dengan unix timestamp
|
||||
// Kirim heartbeat ke Firebase
|
||||
void sendHeartbeat() {
|
||||
// Update lastActive dengan timestamp lokal
|
||||
if (millis() - lastHeartbeatTime >= heartbeatInterval) {
|
||||
lastHeartbeatTime = millis();
|
||||
unsigned long epochTime = time(nullptr);
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActiveWemos", epochTime)) {
|
||||
Serial.println("Heartbeat sent: " + String(epochTime));
|
||||
unsigned long localTime = millis();
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActiveWemos", localTime)) {
|
||||
Serial.println("Heartbeat sent: " + String(localTime));
|
||||
// Tambahkan update status Device Online saat heartbeat berhasil
|
||||
Firebase.setString(firebaseData, "/logs/systemWemos", "Device Online");
|
||||
Serial.println("Device status updated: Online");
|
||||
|
@ -159,62 +327,218 @@ void loop() {
|
|||
if (millis() - lastHeartbeatTime > 70000) {
|
||||
Firebase.setString(firebaseData, "/logs/systemWemos", "Device Offline");
|
||||
}
|
||||
}
|
||||
|
||||
// Cek apakah kartu RFID terdeteksi
|
||||
if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) {
|
||||
Serial.println("Kartu Terdeteksi!");
|
||||
|
||||
// Membaca UID kartu
|
||||
String rfidUID = "";
|
||||
for (byte i = 0; i < mfrc522.uid.size; i++) {
|
||||
rfidUID += String(mfrc522.uid.uidByte[i], HEX);
|
||||
// Fungsi untuk inisialisasi EEPROM jika belum diinisialisasi
|
||||
void initializeEEPROM() {
|
||||
// Cek signature byte
|
||||
if (EEPROM.read(0) != EEPROM_SIGNATURE) {
|
||||
Serial.println("Initializing EEPROM for first use...");
|
||||
// Set signature
|
||||
EEPROM.write(0, EEPROM_SIGNATURE);
|
||||
// Clear card slots
|
||||
for (int i = 1; i < EEPROM_SIZE; i++) {
|
||||
EEPROM.write(i, 0xFF);
|
||||
}
|
||||
EEPROM.commit();
|
||||
Serial.println("EEPROM initialized");
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("UID: ");
|
||||
Serial.println(rfidUID);
|
||||
// Fungsi untuk cek apakah kartu terdaftar di EEPROM
|
||||
bool isCardInEEPROM(String cardId) {
|
||||
int startAddr = 1; // Skip signature byte
|
||||
|
||||
for (int i = 0; i < MAX_CARDS; i++) {
|
||||
int addr = startAddr + (i * CARD_SIZE);
|
||||
if (EEPROM.read(addr) != 0xFF) { // Jika slot tidak kosong
|
||||
char storedCard[CARD_SIZE+1];
|
||||
for (int j = 0; j < CARD_SIZE; j++) {
|
||||
storedCard[j] = char(EEPROM.read(addr + j));
|
||||
}
|
||||
storedCard[CARD_SIZE] = '\0';
|
||||
|
||||
if (cardId == String(storedCard)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// **Cek apakah kartu terdaftar**
|
||||
bool isCardRegistered = false;
|
||||
for (int i = 0; i < sizeof(kartuTerdaftar)/sizeof(kartuTerdaftar[0]); i++) {
|
||||
if (rfidUID == kartuTerdaftar[i]) {
|
||||
isCardRegistered = true;
|
||||
// Fungsi untuk menambahkan kartu ke EEPROM
|
||||
bool addCardToEEPROM(String cardId) {
|
||||
if (cardId.length() != CARD_SIZE) {
|
||||
Serial.println("Card ID harus " + String(CARD_SIZE) + " karakter!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cek apakah kartu sudah terdaftar
|
||||
if (isCardInEEPROM(cardId)) {
|
||||
Serial.println("Kartu sudah terdaftar!");
|
||||
return false;
|
||||
}
|
||||
|
||||
int startAddr = 1; // Skip signature byte
|
||||
bool cardAdded = false;
|
||||
|
||||
// Cari slot kosong
|
||||
for (int i = 0; i < MAX_CARDS; i++) {
|
||||
int addr = startAddr + (i * CARD_SIZE);
|
||||
if (EEPROM.read(addr) == 0xFF) { // Slot kosong
|
||||
// Simpan card ID
|
||||
for (int j = 0; j < CARD_SIZE; j++) {
|
||||
EEPROM.write(addr + j, cardId[j]);
|
||||
}
|
||||
EEPROM.commit();
|
||||
cardAdded = true;
|
||||
Serial.println("Kartu berhasil ditambahkan!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cardAdded) {
|
||||
Serial.println("EEPROM penuh! Hapus beberapa kartu terlebih dahulu.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fungsi untuk menghapus kartu dari EEPROM
|
||||
bool removeCardFromEEPROM(String cardId) {
|
||||
int startAddr = 1; // Skip signature byte
|
||||
bool cardRemoved = false;
|
||||
|
||||
for (int i = 0; i < MAX_CARDS; i++) {
|
||||
int addr = startAddr + (i * CARD_SIZE);
|
||||
if (EEPROM.read(addr) != 0xFF) { // Jika slot tidak kosong
|
||||
char storedCard[CARD_SIZE+1];
|
||||
for (int j = 0; j < CARD_SIZE; j++) {
|
||||
storedCard[j] = char(EEPROM.read(addr + j));
|
||||
}
|
||||
storedCard[CARD_SIZE] = '\0';
|
||||
|
||||
if (cardId == String(storedCard)) {
|
||||
// Hapus card dengan mengisi 0xFF
|
||||
for (int j = 0; j < CARD_SIZE; j++) {
|
||||
EEPROM.write(addr + j, 0xFF);
|
||||
}
|
||||
EEPROM.commit();
|
||||
cardRemoved = true;
|
||||
Serial.println("Kartu berhasil dihapus!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCardRegistered) {
|
||||
Serial.println("Kartu Terdaftar!");
|
||||
|
||||
if (!servoTerbuka) {
|
||||
Serial.println("Membuka kunci...");
|
||||
myServo.write(180);
|
||||
servoTerbuka = true;
|
||||
Firebase.setString(firebaseData, "/smartcab/servo_status", "Terbuka");
|
||||
} else {
|
||||
Serial.println("Mengunci kunci...");
|
||||
myServo.write(0);
|
||||
servoTerbuka = false;
|
||||
Firebase.setString(firebaseData, "/smartcab/servo_status", "Terkunci");
|
||||
}
|
||||
|
||||
// Kirim status ke Firebase
|
||||
Firebase.setString(firebaseData, "/smartcab/last_access", "Terdaftar");
|
||||
Firebase.setString(firebaseData, "/smartcab/status_device", rfidUID);
|
||||
}
|
||||
else {
|
||||
Serial.println("Kartu Tidak Terdaftar! Mengunci servo...");
|
||||
|
||||
// Paksa servo terkunci jika kartu tidak dikenal
|
||||
myServo.write(0);
|
||||
servoTerbuka = false;
|
||||
Firebase.setString(firebaseData, "/smartcab/servo_status", "Terkunci");
|
||||
Firebase.setString(firebaseData, "/smartcab/last_access", "Tidak Terdaftar");
|
||||
Firebase.setString(firebaseData, "/smartcab/status_device", rfidUID);
|
||||
}
|
||||
|
||||
mfrc522.PICC_HaltA(); // Hentikan komunikasi RFID
|
||||
mfrc522.PCD_StopCrypto1();
|
||||
}
|
||||
|
||||
delay(500);
|
||||
|
||||
if (!cardRemoved) {
|
||||
Serial.println("Kartu tidak ditemukan!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fungsi untuk menghapus semua kartu dari EEPROM
|
||||
void clearAllCards() {
|
||||
int startAddr = 1; // Skip signature byte
|
||||
|
||||
for (int i = 0; i < MAX_CARDS * CARD_SIZE; i++) {
|
||||
EEPROM.write(startAddr + i, 0xFF);
|
||||
}
|
||||
EEPROM.commit();
|
||||
Serial.println("Semua kartu berhasil dihapus!");
|
||||
}
|
||||
|
||||
// Fungsi untuk mendapatkan jumlah kartu yang tersimpan di EEPROM
|
||||
int getCardCount() {
|
||||
int startAddr = 1; // Skip signature byte
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < MAX_CARDS; i++) {
|
||||
int addr = startAddr + (i * CARD_SIZE);
|
||||
if (EEPROM.read(addr) != 0xFF) { // Jika slot tidak kosong
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Fungsi untuk upload daftar kartu ke Firebase
|
||||
void uploadCardListToFirebase() {
|
||||
int startAddr = 1; // Skip signature byte
|
||||
int count = 0;
|
||||
|
||||
// Clear existing list
|
||||
Firebase.deleteNode(firebaseData, "/registered_cards/list");
|
||||
|
||||
// Add cards to list
|
||||
for (int i = 0; i < MAX_CARDS; i++) {
|
||||
int addr = startAddr + (i * CARD_SIZE);
|
||||
if (EEPROM.read(addr) != 0xFF) { // Jika slot tidak kosong
|
||||
char storedCard[CARD_SIZE+1];
|
||||
for (int j = 0; j < CARD_SIZE; j++) {
|
||||
storedCard[j] = char(EEPROM.read(addr + j));
|
||||
}
|
||||
storedCard[CARD_SIZE] = '\0';
|
||||
|
||||
String cardKey = "card" + String(count + 1);
|
||||
Firebase.setString(firebaseData, "/registered_cards/list/" + cardKey, String(storedCard));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Update total count
|
||||
Firebase.setInt(firebaseData, "/registered_cards/total", count);
|
||||
|
||||
Serial.println("Daftar kartu berhasil diupload ke Firebase!");
|
||||
}
|
||||
|
||||
// Fungsi untuk memeriksa perintah dari Firebase
|
||||
void checkFirebaseCommands() {
|
||||
// Check for new card to add
|
||||
if (Firebase.getString(firebaseData, "/registered_cards/card")) {
|
||||
String cardId = firebaseData.stringData();
|
||||
|
||||
if (cardId != "") {
|
||||
Serial.println("Perintah baru: tambah kartu " + cardId);
|
||||
|
||||
if (addCardToEEPROM(cardId)) {
|
||||
Firebase.setString(firebaseData, "/registered_cards/status", "Kartu berhasil ditambahkan");
|
||||
uploadCardListToFirebase();
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/registered_cards/status", "Gagal menambahkan kartu");
|
||||
}
|
||||
|
||||
// Reset command
|
||||
Firebase.setString(firebaseData, "/registered_cards/card", "");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for card to delete
|
||||
if (Firebase.getString(firebaseData, "/registered_cards/delete")) {
|
||||
String cardId = firebaseData.stringData();
|
||||
|
||||
if (cardId != "") {
|
||||
Serial.println("Perintah baru: hapus kartu " + cardId);
|
||||
|
||||
if (cardId == "all") {
|
||||
clearAllCards();
|
||||
Firebase.setString(firebaseData, "/registered_cards/status", "Semua kartu berhasil dihapus");
|
||||
uploadCardListToFirebase();
|
||||
} else {
|
||||
if (removeCardFromEEPROM(cardId)) {
|
||||
Firebase.setString(firebaseData, "/registered_cards/status", "Kartu berhasil dihapus");
|
||||
uploadCardListToFirebase();
|
||||
} else {
|
||||
Firebase.setString(firebaseData, "/registered_cards/status", "Kartu tidak ditemukan");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset command
|
||||
Firebase.setString(firebaseData, "/registered_cards/delete", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
$schedule->command('firebase:fetch')->everyMinute();
|
||||
$schedule->command('firebase:fetch')
|
||||
->everySecond();
|
||||
}
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Kreait\Firebase\Contract\Database;
|
||||
|
||||
class CardController extends Controller
|
||||
{
|
||||
protected $database;
|
||||
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$cards = $this->database->getReference('registered_cards/list')->getValue();
|
||||
$total = $this->database->getReference('registered_cards/total')->getValue();
|
||||
$lastCardId = $this->database->getReference('smartcab/status_device')->getValue();
|
||||
$lastAccess = $this->database->getReference('smartcab/last_access')->getValue();
|
||||
|
||||
return view('view_card', compact('cards', 'total', 'lastCardId', 'lastAccess'));
|
||||
}
|
||||
|
||||
public function addCard(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'card_id' => 'required|string|min:7|max:8',
|
||||
]);
|
||||
|
||||
$cardId = $request->input('card_id');
|
||||
$this->database->getReference('registered_cards/card')->set($cardId);
|
||||
|
||||
// Wait for 1.5 seconds before resetting
|
||||
usleep(1500000);
|
||||
|
||||
// Reset the card value to empty string after sending command
|
||||
$this->database->getReference('registered_cards/card')->set('');
|
||||
|
||||
return redirect()->route('view.cards')->with('success', 'Card added successfully!');
|
||||
}
|
||||
|
||||
public function deleteCard($cardId)
|
||||
{
|
||||
$this->database->getReference('registered_cards/delete')->set($cardId);
|
||||
|
||||
// Wait for 1.5 seconds before resetting
|
||||
usleep(1500000);
|
||||
|
||||
// Reset the delete value to empty string after sending command
|
||||
$this->database->getReference('registered_cards/delete')->set('');
|
||||
|
||||
return redirect()->route('view.cards')->with('success', 'Card deletion requested');
|
||||
}
|
||||
|
||||
public function deleteAllCards()
|
||||
{
|
||||
$this->database->getReference('registered_cards/delete')->set('all');
|
||||
|
||||
// Wait for 1.5 seconds before resetting
|
||||
usleep(1500000);
|
||||
|
||||
// Reset the delete value to empty string after sending command
|
||||
$this->database->getReference('registered_cards/delete')->set('');
|
||||
|
||||
return redirect()->route('view.cards')->with('success', 'All cards deletion requested');
|
||||
}
|
||||
}
|
|
@ -53,7 +53,6 @@
|
|||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800">Laporan Keamanan dan Monitoring</h2>
|
||||
|
@ -214,37 +213,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tambahkan ini di dalam form filter, setelah Time Range Picker -->
|
||||
<div class="md:col-span-2">
|
||||
<label for="categories" class="block mb-2 text-sm font-medium text-gray-700">Filter Kategori</label>
|
||||
<select id="categories" data-te-select-init multiple
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
|
||||
<optgroup label="Keamanan">
|
||||
<option value="motion">Motion</option>
|
||||
<option value="status">Status Keamanan</option>
|
||||
<option value="fan">Fan</option>
|
||||
</optgroup>
|
||||
<optgroup label="Perangkat">
|
||||
<option value="servo-status">Servo Status</option>
|
||||
<option value="last-access">Last Access</option>
|
||||
<option value="device">Device Status</option>
|
||||
</optgroup>
|
||||
<optgroup label="Kontrol">
|
||||
<option value="restart-esp">Restart ESP</option>
|
||||
<option value="restart-wemos">Restart Wemos</option>
|
||||
</optgroup>
|
||||
<optgroup label="Sensor">
|
||||
<option value="rfid">RFID</option>
|
||||
<option value="dht">DHT</option>
|
||||
<option value="mpu">MPU</option>
|
||||
</optgroup>
|
||||
<optgroup label="Log">
|
||||
<option value="servo-log">Servo Log</option>
|
||||
<option value="system-esp">System ESP</option>
|
||||
<option value="system-wemos">System Wemos</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Remove the categories filter section -->
|
||||
|
||||
<div class="md:col-span-2 flex justify-end space-x-2">
|
||||
<button type="button" id="applyFilter" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5">
|
||||
|
|
|
@ -0,0 +1,463 @@
|
|||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RFID Card Management</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.2.0/flowbite.min.css" rel="stylesheet" />
|
||||
<style>
|
||||
.highlight {
|
||||
animation: highlight-row 2s ease-in-out;
|
||||
}
|
||||
@keyframes highlight-row {
|
||||
0% { background-color: #fff; }
|
||||
50% { background-color: #d1ecf1; }
|
||||
100% { background-color: #fff; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
||||
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-2xl font-bold text-gray-800">RFID Card Management</h2>
|
||||
<a href="{{route('welcome')}}" class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
|
||||
</svg>
|
||||
Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@if (session('success'))
|
||||
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50" role="alert">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Last Tapped Card Panel -->
|
||||
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm mb-6">
|
||||
<div class="mb-4 border-b border-gray-200 pb-3">
|
||||
<h5 class="text-lg font-medium text-gray-900 flex items-center">
|
||||
<svg class="w-6 h-6 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
|
||||
</svg>
|
||||
Last Tapped Card
|
||||
</h5>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="p-3 bg-gray-50 rounded-lg">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm font-medium text-gray-700">Card ID:</span>
|
||||
<span id="last-card-id" class="font-semibold text-blue-600">{{ $lastCardId ?? 'N/A' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 bg-gray-50 rounded-lg">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm font-medium text-gray-700">Status:</span>
|
||||
<span id="last-access" class="font-semibold {{ $lastAccess == 'Terdaftar' ? 'text-green-600' : 'text-red-600' }}">{{ $lastAccess ?? 'N/A' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
||||
<!-- Combined Add New Card and Registered Cards Panel -->
|
||||
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm">
|
||||
<div class="mb-4 border-b border-gray-200 pb-3">
|
||||
<h5 class="text-lg font-medium text-gray-900 flex items-center">
|
||||
<svg class="w-6 h-6 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
|
||||
</svg>
|
||||
Card Management
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<!-- Add New Card Form -->
|
||||
<div class="mb-6">
|
||||
<button type="button" id="startRegistration"
|
||||
class="text-white bg-green-600 hover:bg-green-700 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm px-4 py-2.5 inline-flex items-center whitespace-nowrap">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
Add Card
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Registered Cards Table -->
|
||||
<div class="mt-6">
|
||||
<h6 class="text-md font-medium text-gray-800 mb-3 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
</svg>
|
||||
Registered Cards
|
||||
</h6>
|
||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
|
||||
<table class="w-full text-sm text-left text-gray-500">
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3">No.</th>
|
||||
<th scope="col" class="px-6 py-3">Card ID</th>
|
||||
<th scope="col" class="px-6 py-3">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if(!empty($cards))
|
||||
@foreach($cards as $key => $cardId)
|
||||
<tr class="bg-white border-b hover:bg-gray-50 {{ $cardId == $lastCardId ? 'highlight' : '' }}">
|
||||
<td class="px-6 py-4">{{ $loop->iteration }}</td>
|
||||
<td class="px-6 py-4">{{ $cardId }}</td>
|
||||
<td class="px-6 py-4">
|
||||
<a href="{{ route('cards.delete', $cardId) }}"
|
||||
onclick="return confirm('Are you sure you want to delete this card?')"
|
||||
class="text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs px-3 py-1.5 inline-flex items-center">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<tr class="bg-white border-b">
|
||||
<td colspan="3" class="px-6 py-4 text-center text-gray-500">No cards registered</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- System Status Panel -->
|
||||
<div class="p-4 bg-white border border-gray-200 rounded-lg shadow-sm">
|
||||
<div class="mb-4 border-b border-gray-200 pb-3">
|
||||
<h5 class="text-lg font-medium text-gray-900 flex items-center">
|
||||
<svg class="w-6 h-6 mr-2 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
System Status
|
||||
</h5>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm font-medium text-gray-700 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
</svg>
|
||||
Total Cards:
|
||||
</span>
|
||||
<span class="font-semibold">{{ $total ?? 0 }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm font-medium text-gray-700 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
System Status:
|
||||
</span>
|
||||
<span id="system-status" class="font-semibold text-gray-800">Loading...</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm font-medium text-gray-700 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"></path>
|
||||
</svg>
|
||||
RFID Status:
|
||||
</span>
|
||||
<span id="rfid-status" class="font-semibold text-gray-800">Loading...</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
|
||||
<span class="text-sm font-medium text-gray-700 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
</svg>
|
||||
Servo Status:
|
||||
</span>
|
||||
<span id="servo-status" class="font-semibold text-gray-800">Loading...</span>
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
<button onclick="if(confirm('Are you sure you want to delete ALL cards?')) window.location.href='{{ route('cards.delete.all') }}'"
|
||||
class="text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex items-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
Delete All Cards
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
|
||||
<script src="https://www.gstatic.com/firebasejs/8.10.1/firebase-database.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.2.0/flowbite.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<script>
|
||||
// Firebase configuration - make sure to use your project's actual config
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyAw9f5XkTkMg-gPE8tnLYBhTibnFyLCHG0",
|
||||
authDomain: "smartcab-8bb42.firebaseapp.com",
|
||||
databaseURL: "https://smartcab-8bb42-default-rtdb.firebaseio.com",
|
||||
projectId: "smartcab-8bb42",
|
||||
storageBucket: "smartcab-8bb42.appspot.com",
|
||||
messagingSenderId: "724750966822",
|
||||
appId: "1:724750966822:web:6d8af1a18e8d8b5cbc0279"
|
||||
};
|
||||
|
||||
// Initialize Firebase
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
const database = firebase.database();
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Listen for real-time updates to device status
|
||||
database.ref('logs').on('value', (snapshot) => {
|
||||
const data = snapshot.val();
|
||||
if (data) {
|
||||
// System status update
|
||||
if (data.systemWemos) {
|
||||
const systemStatus = document.getElementById('system-status');
|
||||
systemStatus.textContent = data.systemWemos;
|
||||
|
||||
if (data.systemWemos === 'Device Online') {
|
||||
systemStatus.classList.add('text-green-600');
|
||||
systemStatus.classList.remove('text-red-600', 'text-gray-800');
|
||||
} else {
|
||||
systemStatus.classList.add('text-red-600');
|
||||
systemStatus.classList.remove('text-green-600', 'text-gray-800');
|
||||
}
|
||||
}
|
||||
|
||||
// RFID status update
|
||||
if (data.RFID && data.RFID.status) {
|
||||
const rfidStatus = document.getElementById('rfid-status');
|
||||
rfidStatus.textContent = data.RFID.status;
|
||||
|
||||
if (data.RFID.status === 'Connected') {
|
||||
rfidStatus.classList.add('text-green-600');
|
||||
rfidStatus.classList.remove('text-red-600', 'text-gray-800');
|
||||
} else {
|
||||
rfidStatus.classList.add('text-red-600');
|
||||
rfidStatus.classList.remove('text-green-600', 'text-gray-800');
|
||||
}
|
||||
}
|
||||
|
||||
// Servo status update
|
||||
if (data.servo && data.servo.status) {
|
||||
const servoStatus = document.getElementById('servo-status');
|
||||
servoStatus.textContent = data.servo.status;
|
||||
|
||||
if (data.servo.status === 'Connected') {
|
||||
servoStatus.classList.add('text-green-600');
|
||||
servoStatus.classList.remove('text-blue-600', 'text-gray-800');
|
||||
} else {
|
||||
servoStatus.classList.add('text-red-600');
|
||||
servoStatus.classList.remove('text-green-600', 'text-gray-800');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for real-time updates to card data
|
||||
database.ref('smartcab').on('value', (snapshot) => {
|
||||
const data = snapshot.val();
|
||||
if (data) {
|
||||
// Update last tapped card
|
||||
if (data.status_device) {
|
||||
const lastCardId = document.getElementById('last-card-id');
|
||||
lastCardId.textContent = data.status_device;
|
||||
|
||||
// Highlight the corresponding row
|
||||
highlightCardRow(data.status_device);
|
||||
}
|
||||
|
||||
// Update access status
|
||||
if (data.last_access) {
|
||||
const lastAccess = document.getElementById('last-access');
|
||||
lastAccess.textContent = data.last_access;
|
||||
|
||||
if (data.last_access === 'Terdaftar') {
|
||||
lastAccess.classList.add('text-green-600');
|
||||
lastAccess.classList.remove('text-red-600');
|
||||
} else {
|
||||
lastAccess.classList.add('text-red-600');
|
||||
lastAccess.classList.remove('text-green-600');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for real-time updates to registered cards count
|
||||
database.ref('registered_cards/total').on('value', (snapshot) => {
|
||||
const totalCards = snapshot.val();
|
||||
const totalElement = document.querySelector('.flex.justify-between.items-center.p-3.bg-gray-50.rounded-lg:first-child .font-semibold');
|
||||
if (totalElement) {
|
||||
totalElement.textContent = totalCards || 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for changes to the card list
|
||||
database.ref('registered_cards/list').on('value', (snapshot) => {
|
||||
const cards = snapshot.val();
|
||||
// This would require refreshing the table, but complex to do without a page reload
|
||||
// Instead, show a notification that new data is available
|
||||
if (cards && Object.keys(cards).length > 0) {
|
||||
const tableBody = document.querySelector('tbody');
|
||||
const currentCardCount = tableBody.querySelectorAll('tr:not(.empty-row)').length;
|
||||
|
||||
if (Object.keys(cards).length !== currentCardCount) {
|
||||
showUpdateNotification();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function showUpdateNotification() {
|
||||
// Create notification if it doesn't exist
|
||||
if (!document.getElementById('update-notification')) {
|
||||
const notification = document.createElement('div');
|
||||
notification.id = 'update-notification';
|
||||
notification.className = 'fixed bottom-4 right-4 bg-blue-600 text-white px-4 py-2 rounded-lg shadow-lg flex items-center space-x-2';
|
||||
notification.innerHTML = `
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
<span>Card list updated!</span>
|
||||
<button class="ml-2 text-white hover:text-gray-200" onclick="location.reload()">Refresh</button>
|
||||
`;
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Auto-remove after 10 seconds
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to highlight the card row if found in the table
|
||||
function highlightCardRow(cardId) {
|
||||
const rows = document.querySelectorAll('tbody tr');
|
||||
rows.forEach(row => {
|
||||
// Remove any existing highlights
|
||||
row.classList.remove('highlight');
|
||||
|
||||
const cardCell = row.querySelector('td:nth-child(2)');
|
||||
if (cardCell && cardCell.textContent.trim() === cardId) {
|
||||
row.classList.add('highlight');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const startRegistrationBtn = document.getElementById('startRegistration');
|
||||
let lastScannedCard = null;
|
||||
let registrationInProgress = false;
|
||||
|
||||
// Fungsi untuk menampilkan popup "Tempelkan Kartu"
|
||||
function showScanPrompt() {
|
||||
Swal.fire({
|
||||
title: 'Tempelkan Kartu',
|
||||
html: '<div class="text-center">' +
|
||||
'<div class="mb-4">' +
|
||||
'<svg class="mx-auto animate-pulse w-16 h-16 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">' +
|
||||
'<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>' +
|
||||
'</svg>' +
|
||||
'</div>' +
|
||||
'<p class="text-gray-500">Silakan tempelkan kartu RFID pada reader</p>' +
|
||||
'</div>',
|
||||
showConfirmButton: false,
|
||||
allowOutsideClick: false,
|
||||
allowEscapeKey: false,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Batal',
|
||||
cancelButtonColor: '#d33',
|
||||
});
|
||||
}
|
||||
|
||||
// Fungsi untuk konfirmasi pendaftaran kartu
|
||||
function confirmCardRegistration(cardId) {
|
||||
Swal.fire({
|
||||
title: 'Konfirmasi Pendaftaran',
|
||||
html: `<div class="text-center">` +
|
||||
`<p class="mb-2">ID Kartu terdeteksi:</p>` +
|
||||
`<p class="text-lg font-semibold text-blue-600">${cardId}</p>` +
|
||||
`<p class="mt-4">Apakah Anda ingin mendaftarkan kartu ini?</p>` +
|
||||
`</div>`,
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Ya, Daftarkan',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
registerCard(cardId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fungsi untuk mendaftarkan kartu
|
||||
async function registerCard(cardId) {
|
||||
try {
|
||||
const response = await fetch('{{ route('cards.add') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
body: JSON.stringify({ card_id: cardId })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
Swal.fire({
|
||||
title: 'Berhasil!',
|
||||
text: 'Kartu berhasil didaftarkan',
|
||||
icon: 'success',
|
||||
confirmButtonColor: '#3085d6'
|
||||
}).then(() => {
|
||||
// Reload halaman untuk memperbarui daftar kartu
|
||||
window.location.reload();
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Terjadi kesalahan saat mendaftarkan kartu');
|
||||
}
|
||||
} catch (error) {
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: error.message,
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Listener untuk tombol Add Card
|
||||
startRegistrationBtn.addEventListener('click', function() {
|
||||
showScanPrompt();
|
||||
registrationInProgress = true;
|
||||
});
|
||||
|
||||
// Listener untuk data Firebase
|
||||
database.ref('smartcab').on('value', (snapshot) => {
|
||||
const data = snapshot.val();
|
||||
if (data && data.status_device && registrationInProgress) {
|
||||
const cardId = data.status_device;
|
||||
|
||||
// Hanya tampilkan konfirmasi jika kartu berbeda dari sebelumnya
|
||||
if (cardId !== lastScannedCard) {
|
||||
lastScannedCard = cardId;
|
||||
Swal.close(); // Tutup popup "Tempelkan Kartu"
|
||||
confirmCardRegistration(cardId);
|
||||
registrationInProgress = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -29,15 +29,19 @@
|
|||
{{-- <a href="{{route('ai.chat')}}" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white">
|
||||
AI
|
||||
</a> --}}
|
||||
<!-- Notification Button Mobile -->
|
||||
<button
|
||||
@click="isNotificationsPanelOpen = true"
|
||||
class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white"
|
||||
>
|
||||
<!-- History Button Mobile (Changed from Notification) -->
|
||||
<a href="{{route('reports')}}" class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
<a href="{{ route('view.cards') }}" class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 6h16M4 10h16M4 14h6m2 0h6m-16 4h16a2 2 0 002-2V8a2 2 0 00-2-2H4a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
|
||||
<!-- Mobile Menu Button -->
|
||||
<button id="mobileMenuBtn" class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white">
|
||||
|
@ -55,15 +59,18 @@ class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-
|
|||
</a> --}}
|
||||
|
||||
|
||||
<!-- Notification Button -->
|
||||
<button
|
||||
@click="isNotificationsPanelOpen = true"
|
||||
class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white"
|
||||
>
|
||||
<!-- History Button (Changed from Notification) -->
|
||||
<a href="{{route('reports')}}" class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</a>
|
||||
<a href="{{ route('view.cards') }}" class="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-white">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 6h16M4 10h16M4 14h6m2 0h6m-16 4h16a2 2 0 002-2V8a2 2 0 00-2-2H4a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<!-- Dark Mode Toggle -->
|
||||
<button id="darkModeToggle" class="p-2 text-gray-500 dark:text-gray-400">
|
||||
|
@ -1340,22 +1347,23 @@ function forceRefreshDeviceStatus() {
|
|||
|
||||
// Fungsi untuk memeriksa status online/offline perangkat
|
||||
function checkDeviceStatus() {
|
||||
const currentTime = Math.floor(Date.now() / 1000); // Konversi ke detik
|
||||
console.log('Checking device status based on data changes...');
|
||||
|
||||
// Tambahkan pengecekan lebih agresif untuk ESP
|
||||
database.ref('device/lastActive').once('value', (snapshot) => {
|
||||
const lastActiveESP = snapshot.val();
|
||||
|
||||
if (lastActiveESP) {
|
||||
const timeDiff = currentTime - lastActiveESP;
|
||||
// Ambil nilai data sebelumnya untuk ESP jika tersedia
|
||||
const previousDataESP = localStorage.getItem('previousESPData');
|
||||
const currentDataESP = JSON.stringify(lastActiveESP);
|
||||
|
||||
console.log('ESP8266 last active: ' + lastActiveESP);
|
||||
console.log('Current time: ' + currentTime);
|
||||
console.log('Time difference: ' + timeDiff + ' seconds');
|
||||
console.log('ESP8266 previous data: ' + previousDataESP);
|
||||
console.log('ESP8266 current data: ' + currentDataESP);
|
||||
|
||||
// Jika perbedaan waktu lebih dari 65 detik, set status offline
|
||||
if (timeDiff > 60) {
|
||||
console.log('ESP8266 terdeteksi offline - mengirim status ke Firebase...');
|
||||
// Jika data tidak berubah sejak pengecekan terakhir, anggap offline
|
||||
if (previousDataESP && previousDataESP === currentDataESP) {
|
||||
console.log('ESP8266 terdeteksi offline - tidak ada perubahan data');
|
||||
|
||||
database.ref('logs/systemESP').set('Device offline')
|
||||
.then(() => {
|
||||
|
@ -1364,6 +1372,13 @@ function checkDeviceStatus() {
|
|||
.catch(error => {
|
||||
console.error('Error updating ESP status:', error);
|
||||
});
|
||||
} else {
|
||||
// Data berubah, perangkat dianggap online
|
||||
console.log('ESP8266 terdeteksi online - data berubah');
|
||||
database.ref('logs/systemESP').set('Device online');
|
||||
|
||||
// Simpan data saat ini untuk pengecekan berikutnya
|
||||
localStorage.setItem('previousESPData', currentDataESP);
|
||||
}
|
||||
} else {
|
||||
// Jika lastActive tidak ada, set status offline
|
||||
|
@ -1377,15 +1392,16 @@ function checkDeviceStatus() {
|
|||
const lastActiveWemos = snapshot.val();
|
||||
|
||||
if (lastActiveWemos) {
|
||||
const timeDiff = currentTime - lastActiveWemos;
|
||||
// Ambil nilai data sebelumnya untuk Wemos jika tersedia
|
||||
const previousData = localStorage.getItem('previousWemosData');
|
||||
const currentData = JSON.stringify(lastActiveWemos);
|
||||
|
||||
console.log('Wemos D1 Mini last active: ' + lastActiveWemos);
|
||||
console.log('Current time: ' + currentTime);
|
||||
console.log('Time difference: ' + timeDiff + ' seconds');
|
||||
console.log('Wemos D1 Mini previous data: ' + previousData);
|
||||
console.log('Wemos D1 Mini current data: ' + currentData);
|
||||
|
||||
// Jika perbedaan waktu lebih dari 65 detik, set status offline
|
||||
if (timeDiff > 60) {
|
||||
console.log('Wemos D1 Mini terdeteksi offline - mengirim status ke Firebase...');
|
||||
// Jika data tidak berubah sejak pengecekan terakhir, anggap offline
|
||||
if (previousData && previousData === currentData) {
|
||||
console.log('Wemos D1 Mini terdeteksi offline - tidak ada perubahan data');
|
||||
|
||||
database.ref('logs/systemWemos').set('Device Offline')
|
||||
.then(() => {
|
||||
|
@ -1394,6 +1410,13 @@ function checkDeviceStatus() {
|
|||
.catch(error => {
|
||||
console.error('Error updating Wemos status:', error);
|
||||
});
|
||||
} else {
|
||||
// Data berubah, perangkat dianggap online
|
||||
console.log('Wemos D1 Mini terdeteksi online - data berubah');
|
||||
database.ref('logs/systemWemos').set('Device Online');
|
||||
|
||||
// Simpan data saat ini untuk pengecekan berikutnya
|
||||
localStorage.setItem('previousWemosData', currentData);
|
||||
}
|
||||
} else {
|
||||
// Jika lastActiveWemos tidak ada, set status offline
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
use App\Http\Controllers\ProfileController;
|
||||
use App\Http\Controllers\ReportController;
|
||||
use App\Http\Controllers\ReportExportController;
|
||||
use App\Http\Controllers\CardController;
|
||||
|
||||
Route::get('/login', [FirebaseAuthController::class, 'showLogin'])
|
||||
->name('login')
|
||||
|
@ -38,4 +39,29 @@
|
|||
Route::get('/profile', [ProfileController::class, 'index'])->name('profile');
|
||||
Route::post('/profile/update', [ProfileController::class, 'update'])->name('profile.update');
|
||||
Route::get('/reports', [ReportController::class, 'index'])->name('reports');
|
||||
Route::get('/export-reports', [ExportReportController::class, 'exportPdf']);
|
||||
Route::get('/export-reports', [ExportReportController::class, 'exportPdf']);
|
||||
|
||||
// RFID Card Management Routesview.cards
|
||||
Route::get('/cards', [CardController::class, 'index'])->name('view.cards');
|
||||
Route::post('/cards/add', [CardController::class, 'addCard'])->name('cards.add');
|
||||
Route::get('/cards/delete/{cardId}', [CardController::class, 'deleteCard'])->name('cards.delete');
|
||||
Route::get('/cards/delete-all', [CardController::class, 'deleteAllCards'])->name('cards.delete.all');
|
||||
|
||||
// Optional API route for status updates
|
||||
Route::get('/api/device-status', function() {
|
||||
$firebase = app('firebase.database');
|
||||
return response()->json([
|
||||
'system' => $firebase->getReference('logs/systemWemos')->getValue(),
|
||||
'rfid' => $firebase->getReference('logs/RFID/status')->getValue(),
|
||||
'servo' => $firebase->getReference('logs/servo/status')->getValue(),
|
||||
]);
|
||||
});
|
||||
|
||||
// API route for card-status
|
||||
Route::get('/api/card-status', function() {
|
||||
$firebase = app('firebase.database');
|
||||
return response()->json([
|
||||
'cardId' => $firebase->getReference('smartcab/status_device')->getValue(),
|
||||
'access' => $firebase->getReference('smartcab/last_access')->getValue(),
|
||||
]);
|
||||
});
|
26496
storage/app/reports.json
26496
storage/app/reports.json
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue