#include #include // ========================================== // PIN DEFINITIONS (Sama dengan Node 2 - ESP8266) // ========================================== #define LORA_SS D8 // NSS/CS #define LORA_RST D0 // Reset LoRa #define LORA_DIO0 D1 // DIO0 / Interrupt #define BUZZER_PIN D2 // Buzzer #define LED_PIN D3 // LED Status // ========================================== // PACKET STRUCTURE (MUTLAK SAMA dengan Node 1 & Node 2) // ========================================== typedef struct struct_message { char text[220]; // Kapasitas dikurangi untuk 4 variabel sinyal int msgType; // 0=Request, 1=Response, 2=Ping, 3=Pong int packetId; int totalPackets; int senderId; // 1=Node1, 2=Node2, 3=Repeater int rssi_gw; // RSSI yang diterima Gateway float snr_gw; // SNR yang diterima Gateway int rssi_b; // RSSI yang diterima Node B float snr_b; // SNR yang diterima Node B } struct_message; struct_message recvData; // ========================================== // SETUP // ========================================== void setup() { Serial.begin(115200); delay(1000); // Jeda extra agar Serial siap Serial.println("\n--- LoRa Gateway Starting ---"); pinMode(BUZZER_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); digitalWrite(BUZZER_PIN, LOW); digitalWrite(LED_PIN, LOW); // Inisialisasi SPI secara tegas SPI.begin(); LoRa.setPins(LORA_SS, LORA_RST, LORA_DIO0); if (!LoRa.begin(433E6)) { Serial.println("Gagal Inisialisasi LoRa Gateway"); // Indikator Error: Beep 2x cepat setiap 20 detik while (1) { for (int i = 0; i < 2; i++) { digitalWrite(LED_PIN, HIGH); digitalWrite(BUZZER_PIN, HIGH); delay(100); digitalWrite(LED_PIN, LOW); digitalWrite(BUZZER_PIN, LOW); delay(100); } delay(19600); // Jeda hingga mencapai 20 detik total (20000ms - 400ms) } } // LED Nyala terus menandakan alat SIAP/READY digitalWrite(LED_PIN, HIGH); Serial.println("Repeater LoRa (Gateway Perantara) Standby (V2 Piggybacking)"); } // ========================================== // LOOP (TANGKAP & PANTULKAN) // ========================================== void loop() { int packetSize = LoRa.parsePacket(); if (packetSize == sizeof(struct_message)) { LoRa.readBytes((uint8_t*)&recvData, sizeof(recvData)); // 1. CEK IDENTITAS PENGIRIM (Proteksi Broadcast Storm) if (recvData.senderId != 3) { Serial.print("Menerima paket dari Node "); Serial.print(recvData.senderId); Serial.println(". Memantulkan..."); // JIKA PAKET DARI NODE 2 (B) - Berarti jalur Balasan (Downlink) // Kita suntikkan kualitas sinyal Hop 1 (jalur pulang) ke sini if (recvData.senderId == 2) { recvData.rssi_gw = LoRa.packetRssi(); recvData.snr_gw = LoRa.packetSnr(); Serial.println("Downlink: Menyuntikkan Sinyal dari Node B ke Paket"); } // 2. INDIKATOR SUARA & CAHAYA digitalWrite(LED_PIN, LOW); // Matikan LED sebentar digitalWrite(BUZZER_PIN, HIGH); // Bunyikan Buzzer delay(50); digitalWrite(BUZZER_PIN, LOW); digitalWrite(LED_PIN, HIGH); // Nyalakan kembali LED (Ready state) if (recvData.senderId == 1 && recvData.msgType == 2) { struct_message repPong; memset(&repPong, 0, sizeof(repPong)); repPong.msgType = 3; // PONG repPong.packetId = 0; repPong.totalPackets = 1; repPong.senderId = 3; // Identitas Repeater strcpy(repPong.text, "REPEATER_READY"); delay(600); // Beri waktu Node A bersiap & Web App merender state awal LoRa.beginPacket(); LoRa.write((uint8_t*)&repPong, sizeof(repPong)); LoRa.endPacket(); Serial.println("Mengirim status REPEATER_READY ke Node 1"); } // 3. UBAH IDENTITAS PAKET recvData.senderId = 3; // 4. JEDA AMAN UDARA // Gunakan delay cepat (50ms) untuk pengiriman data (chunking) agar tidak memakan waktu lama // Gunakan delay lama (500ms) untuk PING/PONG agar Web App sempat me-render state UI if (recvData.msgType == 0 || recvData.msgType == 1) { delay(50); } else { delay(500); } // 5. PANTULKAN (RE-BROADCAST) LoRa.beginPacket(); LoRa.write((uint8_t*)&recvData, sizeof(recvData)); LoRa.endPacket(); Serial.println("Paket sukses dipantulkan ke udara!"); } } }