250 lines
5.9 KiB
C++
250 lines
5.9 KiB
C++
#include <SPI.h>
|
|
#include <MFRC522.h>
|
|
#include <TinyGPS++.h>
|
|
#include <TinyGsmClient.h>
|
|
#include <ArduinoHttpClient.h>
|
|
#include <ArduinoJson.h>
|
|
#include <math.h>
|
|
|
|
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;
|
|
}
|