#include #include #include #include #include #include #include const char FIREBASE_HOST[] = "sistem-keamanan-c9565-default-rtdb.firebaseio.com"; const String FIREBASE_AUTH = "m34dRlGN86G2xllAm197fVt8VhPj4dfQxKGejjnz"; const int SSL_PORT = 443; const String GPS_PATH = "/gps"; const String RELAY_PATH = "/relay"; char apn[] = "internet"; char user[] = ""; char pass[] = ""; #define rxPin 4 #define txPin 2 HardwareSerial sim800(1); TinyGsm modem(sim800); #define RXD2 16 #define TXD2 17 HardwareSerial neogps(2); TinyGPSPlus gps; TinyGsmClientSecure gsm_client_secure_modem(modem, 0); HttpClient http_client = HttpClient(gsm_client_secure_modem, FIREBASE_HOST, SSL_PORT); unsigned long previousMillis = 0; const long interval = 10000; // Interval hanya untuk relay #define RELAY_PIN 5 #define RST_PIN 22 #define SS_PIN 21 MFRC522 rfid(SS_PIN, RST_PIN); #define BUZZER_PIN 15 bool relayState = false; String registeredRFID[] = {"BEC1596E", "23C13394", "73BE3A1C"}; double prevLatitude = 0.0; double prevLongitude = 0.0; const double DISTANCE_THRESHOLD = 10.0; // 10 meter #define EARTH_RADIUS 6371e3 void setup() { Serial.begin(115200); SPI.begin(); rfid.PCD_Init(); sim800.begin(9600, SERIAL_8N1, rxPin, txPin); neogps.begin(9600, SERIAL_8N1, RXD2, TXD2); delay(3000); pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, HIGH); // Memastikan relay dalam keadaan Normally Closed (NC) pinMode(BUZZER_PIN, OUTPUT); digitalWrite(BUZZER_PIN, LOW); // Memastikan buzzer mati modem.restart(); String modemInfo = modem.getModemInfo(); connectToInternet(); http_client.setHttpResponseTimeout(90 * 1000); // Timeout 90 detik } void loop() { if (!modem.isNetworkConnected()) { connectToInternet(); } // Tangani permintaan HTTP untuk relay secara berkala unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; bool newRelayState = relayState; if (GetRelayStateFromFirebase(&http_client, newRelayState) && newRelayState != relayState) { updateRelayState(newRelayState); } } gps_loop(); // Selalu cek kartu RFID rfid_loop(); } void connectToInternet() { int retry_count = 0; const int max_retries = 5; while (retry_count < max_retries) { if (modem.gprsConnect(apn, user, pass)) { return; } else { retry_count++; delay(2000); // Tunggu sebelum mencoba lagi } } } void PostToFirebase(const char* method, const String & path, const String & data, HttpClient* http) { String response; int statusCode = 0; http->connectionKeepAlive(); // Saat ini diperlukan untuk HTTPS String url; if (path[0] != '/') { url = "/"; } url += path + ".json"; url += "?auth=" + FIREBASE_AUTH; String contentType = "application/json"; http->put(url, contentType, data); statusCode = http->responseStatusCode(); response = http->responseBody(); if (!http->connected()) { http->stop(); // Matikan if (!modem.isNetworkConnected()) { connectToInternet(); } } } bool GetRelayStateFromFirebase(HttpClient* http, bool &relayState) { String url = String(RELAY_PATH) + ".json?auth=" + FIREBASE_AUTH; http->get(url); int statusCode = http->responseStatusCode(); String response = http->responseBody(); if (statusCode == 200) { DynamicJsonDocument doc(1024); deserializeJson(doc, response); relayState = doc["relayState"]; return true; } else { if (!http->connected()) { connectToInternet(); } } return false; } void gps_loop() { boolean newData = false; for (unsigned long start = millis(); millis() - start < 2000; ) { while (neogps.available()) { if (gps.encode(neogps.read())) { newData = true; break; } } } if (newData) { double currentLat = gps.location.lat(); double currentLng = gps.location.lng(); double distance = haversineDistance(prevLatitude, prevLongitude, currentLat, currentLng); if (distance >= DISTANCE_THRESHOLD) { String latitude = String(currentLat, 6); String longitude = String(currentLng, 6); String gpsData = "{"; gpsData += "\"lat\":" + latitude + ","; gpsData += "\"lng\":" + longitude + ""; gpsData += "}"; PostToFirebase("PATCH", GPS_PATH, gpsData, &http_client); prevLatitude = currentLat; prevLongitude = currentLng; } } } void rfid_loop() { if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) { return; } String rfidTag = ""; for (byte i = 0; i < rfid.uid.size; i++) { rfidTag += String(rfid.uid.uidByte[i], HEX); } rfidTag.toUpperCase(); for (String id : registeredRFID) { if (rfidTag == id) { bool newRelayState = !relayState; updateRelayState(newRelayState); break; } } } void updateRelayState(bool newRelayState) { relayState = newRelayState; if (relayState) { buzz(2, 200); } else { buzz(1, 200); } digitalWrite(RELAY_PIN, relayState ? LOW : HIGH); String relayData = "{"; relayData += "\"relayState\":" + String(relayState ? "true" : "false"); relayData += "}"; PostToFirebase("PATCH", RELAY_PATH, relayData, &http_client); } void buzz(int count, int delayTime) { for (int i = 0; i < count; i++) { digitalWrite(BUZZER_PIN, HIGH); delay(delayTime); digitalWrite(BUZZER_PIN, LOW); delay(delayTime); } } double haversineDistance(double lat1, double lon1, double lat2, double lon2) { double lat1Rad = radians(lat1); double lat2Rad = radians(lat2); double deltaLat = radians(lat2 - lat1); double deltaLon = radians(lon2 - lon1); double a = sin(deltaLat / 2) * sin(deltaLat / 2) + cos(lat1Rad) * cos(lat2Rad) * sin(deltaLon / 2) * sin(deltaLon / 2); double c = 2 * atan2(sqrt(a), sqrt(1 - a)); return EARTH_RADIUS * c; }