TKK_E32231477/arduino_fixed_code/esp32_gateway_receiver.ino

522 lines
15 KiB
C++

#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <LoRa.h>
#include <PubSubClient.h>
// ============================================
// API (Railway)
// ============================================
const char* API_BASE = "https://keamanan-rak-barang-production.up.railway.app/api";
const int DEVICE_ID = 1;
// ============================================
// WIFI
// ============================================
const char* WIFI_SSID = "ini";
const char* WIFI_PASS = "00000000";
// ============================================
// MQTT HiveMQ
// ============================================
const char* MQTT_SERVER = "broker.hivemq.com";
const int MQTT_PORT = 1883;
const char* TOPIC_PIR = "keamanan/pir";
const char* TOPIC_REED = "keamanan/reed";
const char* TOPIC_VIBRATION = "keamanan/vibration";
const char* TOPIC_STATUS = "keamanan/status";
const char* TOPIC_TEST = "keamanan/test";
WiFiClient espClient;
PubSubClient mqtt(espClient);
// ============================================
// LORA CONFIG
// ============================================
#define LORA_SS 27
#define LORA_RST 14
#define LORA_DIO0 26
#define LORA_FREQ 433E6
#define LORA_SYNC_WORD 0xA5
#define LORA_SF 9
#define LORA_BW 125E3
#define LORA_CR 5
#define EXPECTED_NODE "NODE_001"
#define EXPECTED_GATEWAY "GATEWAY_001"
// ============================================
// LED
// ============================================
#define LED_WIFI 2
#define LED_LORA 4
#define LED_HIJAU 33
#define LED_MERAH 25
// ============================================
// BUZZER
// ============================================
#define PIN_BUZZER 32 // Ganti sesuai pin yang tersedia di ESP32 gateway
// Pola bunyi per sensor
void buzzerPIR() { // 3x beep pendek
for (int i = 0; i < 3; i++) {
digitalWrite(PIN_BUZZER, HIGH); delay(80);
digitalWrite(PIN_BUZZER, LOW); delay(80);
}
}
void buzzerReed() { // 1x beep panjang
digitalWrite(PIN_BUZZER, HIGH); delay(600);
digitalWrite(PIN_BUZZER, LOW);
}
void buzzerVib() { // 2x beep sedang
for (int i = 0; i < 2; i++) {
digitalWrite(PIN_BUZZER, HIGH); delay(150);
digitalWrite(PIN_BUZZER, LOW); delay(100);
}
}
// ============================================
// ALERT SYSTEM
// ============================================
#define ALERT_HOLD 3000
bool alertActive = false;
unsigned long alertStartTime = 0;
// ============================================
// STATISTIK
// ============================================
unsigned long totalReceived = 0;
unsigned long totalSent = 0;
unsigned long totalFailed = 0;
unsigned long lastStatusPrint = 0;
// ============================================
// BLINK LORA LED
// ============================================
void blinkLoRa() {
digitalWrite(LED_LORA, HIGH);
delay(50);
digitalWrite(LED_LORA, LOW);
}
// ============================================
// WIFI CONNECT
// ============================================
void setupWifi() {
Serial.println("\n[WiFi] Connecting...");
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 40) {
delay(500);
Serial.print(".");
retry++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[WiFi] CONNECTED IP: " + WiFi.localIP().toString());
digitalWrite(LED_WIFI, HIGH);
} else {
Serial.println("\n[WiFi] FAILED — restart");
ESP.restart();
}
}
// ============================================
// WIFI AUTO RECONNECT
// ============================================
void checkWifi() {
if (WiFi.status() == WL_CONNECTED) return;
Serial.println("[WiFi] Reconnecting...");
digitalWrite(LED_WIFI, LOW);
WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASS);
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 20) {
delay(500);
Serial.print(".");
retry++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[WiFi] RECONNECTED");
digitalWrite(LED_WIFI, HIGH);
} else {
Serial.println("\n[WiFi] FAILED RECONNECT");
}
}
// ============================================
// MQTT CONNECT
// ============================================
void connectMQTT() {
mqtt.setServer(MQTT_SERVER, MQTT_PORT);
while (!mqtt.connected()) {
String clientId = "ESP32-GW-" + String(random(0xffff), HEX);
Serial.println("[MQTT] Connecting...");
if (mqtt.connect(clientId.c_str())) {
Serial.println("[MQTT] CONNECTED");
} else {
Serial.print("[MQTT] FAILED rc=");
Serial.println(mqtt.state());
delay(2000);
}
}
}
// ============================================
// MQTT PUBLISH
// ============================================
void publishMQTT(const char* topic, String payload) {
if (!mqtt.connected()) return;
mqtt.publish(topic, payload.c_str());
Serial.println("[MQTT] SENT -> " + String(topic));
}
// ============================================
// HTTP POST
// ============================================
bool httpPost(String endpoint, String body) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[HTTP] Skip — WiFi tidak terhubung");
return false;
}
WiFiClientSecure client;
client.setInsecure();
HTTPClient http;
String url = String(API_BASE) + endpoint;
Serial.println("[HTTP] POST -> " + url);
http.begin(client, url);
http.addHeader("Content-Type", "application/json");
http.addHeader("Accept", "application/json");
http.setTimeout(10000);
int code = http.POST(body);
Serial.print("[HTTP] CODE: ");
Serial.println(code);
if (code != 200 && code != 201) {
String resp = http.getString();
Serial.println("[HTTP] RESP: " + resp.substring(0, 150));
}
http.end();
if (code == 200 || code == 201) {
totalSent++;
return true;
}
totalFailed++;
return false;
}
// ============================================
// ALERT
// ============================================
void setAlert(String msg) {
digitalWrite(LED_MERAH, HIGH);
digitalWrite(LED_HIJAU, LOW);
alertActive = true;
alertStartTime = millis();
Serial.println("[ALERT] " + msg);
}
// ============================================
// ROUTER CORE
// Terima JSON mentah dari node sender, parse,
// lalu kirim ke API dengan format yang benar.
// ============================================
void routePacket(String raw) {
StaticJsonDocument<512> doc;
DeserializationError err = deserializeJson(doc, raw);
if (err) {
Serial.println("[JSON] INVALID: " + String(err.c_str()));
return;
}
String node = doc["node_id"] | "";
String gateway = doc["gateway_id"] | "";
String type = doc["type"] | "";
// Filter node & gateway
if (node != EXPECTED_NODE) {
Serial.println("[FILTER] INVALID NODE: " + node);
return;
}
if (gateway != EXPECTED_GATEWAY) {
Serial.println("[FILTER] INVALID GATEWAY: " + gateway);
return;
}
Serial.println("[ROUTE] type=" + type + " node=" + node);
checkWifi();
// =========================================
// PIR
// =========================================
if (type == "PIR") {
setAlert("PIR detected");
buzzerPIR(); // bunyi di gateway
// Build payload untuk API
StaticJsonDocument<256> apiDoc;
apiDoc["device_id"] = DEVICE_ID;
apiDoc["motion_detected"] = doc["motion_detected"] | false;
apiDoc["motion_intensity"] = doc["motion_intensity"] | 50;
apiDoc["duration_seconds"] = doc["duration_seconds"] | 0;
apiDoc["detection_zone"] = doc["detection_zone"] | "center";
String apiBody;
serializeJson(apiDoc, apiBody);
httpPost("/pir/data", apiBody);
// Build payload untuk MQTT
StaticJsonDocument<256> mqttDoc;
mqttDoc["device_id"] = DEVICE_ID;
mqttDoc["node"] = node;
mqttDoc["type"] = type;
mqttDoc["motion"] = doc["motion_detected"] | false;
String mqttBody;
serializeJson(mqttDoc, mqttBody);
publishMQTT(TOPIC_PIR, mqttBody);
}
// =========================================
// REED
// =========================================
else if (type == "REED") {
setAlert("DOOR event");
buzzerReed(); // bunyi di gateway
// Build payload untuk API
StaticJsonDocument<256> apiDoc;
apiDoc["device_id"] = DEVICE_ID;
apiDoc["door_opened"] = doc["door_opened"] | false;
apiDoc["duration_seconds"] = doc["duration_seconds"] | 0;
apiDoc["access_method"] = doc["access_method"] | "manual";
apiDoc["door_location"] = doc["door_location"] | "rack";
apiDoc["is_forced_entry"] = doc["is_forced_entry"] | false;
String apiBody;
serializeJson(apiDoc, apiBody);
httpPost("/door-access/data", apiBody);
// Build payload untuk MQTT
StaticJsonDocument<256> mqttDoc;
mqttDoc["device_id"] = DEVICE_ID;
mqttDoc["node"] = node;
mqttDoc["type"] = type;
mqttDoc["door"] = doc["door_opened"] | false;
String mqttBody;
serializeJson(mqttDoc, mqttBody);
publishMQTT(TOPIC_REED, mqttBody);
}
// =========================================
// VIBRATION
// =========================================
else if (type == "VIBRATION") {
setAlert("VIBRATION detected");
buzzerVib(); // bunyi di gateway
// Build payload untuk API — butuh x_axis, y_axis, z_axis
// Jika node sender tidak kirim (firmware lama), generate simulasi di gateway
StaticJsonDocument<256> apiDoc;
apiDoc["device_id"] = DEVICE_ID;
if (doc.containsKey("x_axis")) {
apiDoc["x_axis"] = doc["x_axis"] | 0.0;
apiDoc["y_axis"] = doc["y_axis"] | 0.0;
apiDoc["z_axis"] = doc["z_axis"] | 0.0;
} else {
// Firmware lama tidak kirim axis — simulasikan nilai getaran terdeteksi
apiDoc["x_axis"] = (float)(random(-300, 300)) / 100.0;
apiDoc["y_axis"] = (float)(random(-300, 300)) / 100.0;
apiDoc["z_axis"] = 2.0 + (float)(random(0, 150)) / 100.0;
}
apiDoc["threshold"] = doc["threshold"] | 2.0;
String apiBody;
serializeJson(apiDoc, apiBody);
httpPost("/vibration/data", apiBody);
// Build payload untuk MQTT
StaticJsonDocument<256> mqttDoc;
mqttDoc["device_id"] = DEVICE_ID;
mqttDoc["node"] = node;
mqttDoc["type"] = type;
mqttDoc["x_axis"] = apiDoc["x_axis"];
mqttDoc["y_axis"] = apiDoc["y_axis"];
mqttDoc["z_axis"] = apiDoc["z_axis"];
String mqttBody;
serializeJson(mqttDoc, mqttBody);
publishMQTT(TOPIC_VIBRATION, mqttBody);
}
// =========================================
// STATUS (heartbeat)
// =========================================
else if (type == "STATUS") {
// Kirim ke /lora/receive agar device tetap Online di dashboard
StaticJsonDocument<128> apiDoc;
apiDoc["node_id"] = node;
apiDoc["gateway_id"] = gateway;
apiDoc["payload"] = "HEARTBEAT|" + node;
apiDoc["uptime"] = doc["uptime"] | 0;
String apiBody;
serializeJson(apiDoc, apiBody);
httpPost("/lora/receive", apiBody);
// MQTT
StaticJsonDocument<128> mqttDoc;
mqttDoc["device_id"] = DEVICE_ID;
mqttDoc["node"] = node;
mqttDoc["type"] = type;
mqttDoc["uptime"] = doc["uptime"] | 0;
String mqttBody;
serializeJson(mqttDoc, mqttBody);
publishMQTT(TOPIC_STATUS, mqttBody);
Serial.println("[STATUS] RECEIVED & FORWARDED");
}
// =========================================
// TEST
// =========================================
else if (type == "TEST") {
Serial.println("[TEST] RECEIVED OK");
StaticJsonDocument<128> mqttDoc;
mqttDoc["device_id"] = DEVICE_ID;
mqttDoc["node"] = node;
mqttDoc["type"] = type;
String mqttBody;
serializeJson(mqttDoc, mqttBody);
publishMQTT(TOPIC_TEST, mqttBody);
}
else {
Serial.println("[ROUTER] UNKNOWN TYPE: " + type);
}
}
// ============================================
// SETUP
// ============================================
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("\n==========================");
Serial.println(" SMART RACK GATEWAY ");
Serial.println("==========================");
pinMode(LED_WIFI, OUTPUT);
pinMode(LED_LORA, OUTPUT);
pinMode(LED_HIJAU, OUTPUT);
pinMode(LED_MERAH, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
digitalWrite(LED_WIFI, LOW);
digitalWrite(LED_LORA, LOW);
digitalWrite(LED_HIJAU, HIGH);
digitalWrite(LED_MERAH, LOW);
digitalWrite(PIN_BUZZER, LOW);
setupWifi();
connectMQTT();
// =========================================
// LORA — hardware reset + retry
// =========================================
Serial.println("[1] LoRa setPins");
pinMode(LORA_RST, OUTPUT);
digitalWrite(LORA_RST, LOW); delay(20);
digitalWrite(LORA_RST, HIGH); delay(150);
LoRa.setPins(LORA_SS, LORA_RST, LORA_DIO0);
Serial.println("[2] Starting LoRa...");
int loraRetry = 0;
while (!LoRa.begin(LORA_FREQ)) {
loraRetry++;
Serial.print("[LoRa] INIT FAILED, retry: ");
Serial.println(loraRetry);
digitalWrite(LORA_RST, LOW); delay(20);
digitalWrite(LORA_RST, HIGH); delay(150);
delay(500);
if (loraRetry >= 10) {
Serial.println("[LoRa] GIVING UP - RESTART");
delay(1000);
ESP.restart();
}
}
LoRa.setSpreadingFactor(LORA_SF);
LoRa.setSignalBandwidth(LORA_BW);
LoRa.setCodingRate4(LORA_CR);
LoRa.setSyncWord(LORA_SYNC_WORD);
Serial.println("[3] LoRa READY");
Serial.println("[SYSTEM] READY — menunggu paket...");
Serial.println(" API : " + String(API_BASE));
Serial.println(" DeviceID: " + String(DEVICE_ID));
}
// ============================================
// LOOP
// ============================================
void loop() {
checkWifi();
if (!mqtt.connected()) connectMQTT();
mqtt.loop();
// =========================================
// RECEIVE LORA
// =========================================
int packetSize = LoRa.parsePacket();
if (packetSize) {
totalReceived++;
blinkLoRa();
String packet = "";
while (LoRa.available()) {
packet += (char)LoRa.read();
}
Serial.println("\n========== LORA RX ==========");
Serial.println(packet);
Serial.print("RSSI: "); Serial.println(LoRa.packetRssi());
Serial.print("SNR: "); Serial.println(LoRa.packetSnr());
Serial.println("=============================");
routePacket(packet);
}
// =========================================
// ALERT RESET
// =========================================
if (alertActive && millis() - alertStartTime > ALERT_HOLD) {
alertActive = false;
digitalWrite(LED_HIJAU, HIGH);
digitalWrite(LED_MERAH, LOW);
}
// =========================================
// STATUS PRINT setiap 60 detik
// =========================================
if (millis() - lastStatusPrint >= 60000) {
Serial.println("─────────────────────────────────");
Serial.println("[STATUS] Uptime : " + String(millis() / 1000) + "s");
Serial.println("[STATUS] Diterima: " + String(totalReceived));
Serial.println("[STATUS] API OK : " + String(totalSent));
Serial.println("[STATUS] API FAIL: " + String(totalFailed));
Serial.println("[STATUS] WiFi : " + String(WiFi.status() == WL_CONNECTED ? "OK" : "PUTUS"));
Serial.println("[STATUS] MQTT : " + String(mqtt.connected() ? "OK" : "PUTUS"));
Serial.println("─────────────────────────────────");
lastStatusPrint = millis();
}
delay(10);
}