diff --git a/ProgramArduino/coding.ino b/ProgramArduino/coding.ino new file mode 100644 index 0000000..8be831c --- /dev/null +++ b/ProgramArduino/coding.ino @@ -0,0 +1,249 @@ +#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; +}