#include <HardwareSerial.h>
#include <Wire.h> // Untuk komunikasi I2C OLED
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h> // Pustaka untuk konektivitas WiFi
#include <WiFiClient.h> // Untuk melakukan koneksi TCP sebagai "ping"
// Definisikan pin RX dan TX untuk komunikasi serial antara ESP32 dan SIM800L
#define SIM800L_RX_PIN 16 // Pin RX ESP32 terhubung ke TX SIM800L
#define SIM800L_TX_PIN 17 // Pin TX ESP32 terhubung ke RX SIM800L
// Definisikan pin untuk LED indikator
#define LED_PIN 2 // Contoh pin GPIO2 untuk LED, bisa diganti sesuai kebutuhan
// Definisikan pin untuk tombol fisik
#define BUTTON_PIN 4 // Contoh pin GPIO4 untuk tombol, bisa diganti sesuai kebutuhan
// Sambungkan satu sisi tombol ke pin ini, dan sisi lain ke GND.
// Resistor pull-up internal akan diaktifkan.
// Ukuran layar OLED (128x64)
#define SCREEN_WIDTH 128 // Lebar piksel OLED
#define SCREEN_HEIGHT 64 // Tinggi piksel OLED
// Kredensial WiFi Anda
const char* WIFI_SSID = "Dara@home";
const char* WIFI_PASSWORD = "rejeki88";
// Deklarasi objek SSD1306 (OLED I2C address 0x3C atau 0x3D)
// Ganti 0x3C jika OLED Anda menggunakan alamat 0x3D
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Buat objek HardwareSerial untuk SIM800L
HardwareSerial sim800lSerial(1); // Gunakan UART1 pada ESP32 (UART0 digunakan untuk Serial debugging)
// --- Deklarasi Fungsi Prototipe ---
String sendATCommand(String command);
void getAndDisplaySignalStrength();
void sendSMS(String phoneNumber, String message);
void setLedStatus(bool pingSuccess);
void makeCall(String phoneNumber, int callDurationSeconds);
void connectWiFi(); // Fungsi baru untuk menghubungkan ke WiFi
bool testGatewayPing(); // Fungsi baru untuk menguji ping ke gateway
// Variabel untuk debouncing tombol
long lastButtonPressTime = 0; // Waktu terakhir tombol ditekan
const long debounceDelay = 50; // Waktu debounce dalam milidetik
void setup() {
// Inisialisasi komunikasi serial untuk debugging (monitor serial)
Serial.begin(115200);
Serial.println("Memulai pengujian koneksi ESP32 dengan SIM800L, OLED, LED, Tombol, dan WiFi...");
// Inisialisasi pin LED sebagai output
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // Pastikan LED mati di awal inisialisasi
// Inisialisasi pin tombol sebagai input dengan resistor pull-up internal
// Tombol harus disambungkan untuk menghubungkan pin ini ke GND saat ditekan.
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.println("Pin tombol diinisialisasi dengan INPUT_PULLUP.");
// Inisialisasi OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Alamat I2C umum untuk OLED
Serial.println(F("Alokasi SSD1306 gagal"));
for (;;) ; // Jangan lanjutkan jika gagal, berhenti di sini
}
display.display(); // Tampilkan logo boot-up Adafruit
delay(2000);
display.clearDisplay(); // Hapus tampilan
display.setTextSize(1); // Ukuran teks 1
display.setTextColor(SSD1306_WHITE); // Warna teks putih
// Tampilkan pesan inisialisasi di OLED
display.setCursor(0, 0);
display.println("ESP32 + SIM800L");
display.println("Inisialisasi...");
display.display();
delay(2000);
// Inisialisasi komunikasi serial untuk SIM800L
// Baud rate 9600, 8 bit data, tanpa paritas, 1 bit stop
sim800lSerial.begin(9600, SERIAL_8N1, SIM800L_RX_PIN, SIM800L_TX_PIN);
delay(1000); // Beri waktu modul untuk stabil
// --- Pengujian Modul SIM800L dan Indikator LED ---
Serial.println("Mengirim AT command untuk memeriksa koneksi SIM800L...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Cek Koneksi GSM...");
display.display();
String atResponse = sendATCommand("AT");
setLedStatus(atResponse.indexOf("OK") != -1);
delay(1000);
Serial.println("Mengirim AT+CSQ untuk memeriksa kualitas sinyal SIM800L...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Mengecek Sinyal GSM...");
display.display();
getAndDisplaySignalStrength();
delay(2000);
Serial.println("Mengirim AT+CREG? untuk memeriksa pendaftaran jaringan SIM800L...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Mendaftar Jaringan GSM...");
display.display();
String cregResponse = sendATCommand("AT+CREG?");
setLedStatus(cregResponse.indexOf("OK") != -1);
delay(2000);
Serial.println("Mencoba mengirim SMS dengan SIM800L...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Mengirim SMS...");
display.display();
sendSMS("+628112508805", "Halo dari ESP32 dan SIM800L!");
delay(3000);
// --- Koneksi WiFi Awal ---
connectWiFi(); // Lakukan koneksi WiFi di awal
// Final test message on OLED
display.clearDisplay();
display.setCursor(0, 0);
display.println("Inisialisasi Selesai!");
display.println("Tekan Tombol utk Panggil.");
display.println("Cek PING Gateway.");
display.display();
}
void loop() {
// Logic ping SIM800L dan kekuatan sinyal
static unsigned long lastSim800lPingTime = 0;
static unsigned long sim800lPingInterval = 10000; // Ping SIM800L setiap 10 detik
if (millis() - lastSim800lPingTime >= sim800lPingInterval) {
lastSim800lPingTime = millis();
Serial.println("Melakukan ping SIM800L (AT command) untuk indikator LED...");
String atResponseLoop = sendATCommand("AT");
setLedStatus(atResponseLoop.indexOf("OK") != -1);
getAndDisplaySignalStrength(); // Memperbarui kekuatan sinyal di OLED dan LED
}
// --- Logic Koneksi WiFi dan Ping Gateway ---
static unsigned long lastGatewayPingTime = 0;
static unsigned long gatewayPingInterval = 30000; // Cek gateway setiap 30 detik
static bool callInitiatedDueToPingFailure = false;
static unsigned long lastCallDueToPingTime = 0;
const unsigned long callCooldown = 5 * 60 * 1000; // Cooldown 5 menit untuk panggilan yang dipicu kegagalan ping
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi tidak terhubung. Mencoba menyambung kembali...");
connectWiFi(); // Coba sambungkan kembali jika tidak terhubung
}
if (WiFi.status() == WL_CONNECTED && (millis() - lastGatewayPingTime >= gatewayPingInterval)) {
lastGatewayPingTime = millis();
Serial.println("Melakukan Uji Ping Gateway...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Memeriksa Gateway...");
display.display();
if (testGatewayPing()) { // Jika ping berhasil
Serial.println("Ping Gateway Berhasil (koneksi WiFi baik).");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Gateway OK!");
display.println("WiFi Connected.");
display.display();
callInitiatedDueToPingFailure = false; // Reset flag panggilan jika gateway dapat dijangkau
} else { // Jika ping timeout
Serial.println("Ping Gateway Timeout! Memulai panggilan via SIM800L...");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Gateway Timeout!");
display.println("Memanggil via SIM800L...");
display.display();
if (!callInitiatedDueToPingFailure || (millis() - lastCallDueToPingTime >= callCooldown)) {
makeCall("+628112508805", 15); // Lakukan panggilan 15 detik
callInitiatedDueToPingFailure = true;
lastCallDueToPingTime = millis();
} else {
Serial.println("Panggilan telah dipicu baru-baru ini karena kegagalan ping. Menunggu cooldown...");
}
}
}
// --- Logic Pengecekan Tombol ---
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW && (millis() - lastButtonPressTime) > debounceDelay) {
if (lastButtonPressTime == 0) { // Hanya picu jika ini penekanan baru
Serial.println("Tombol Ditekan! Memulai panggilan...");
display.clearDisplay();
display.setCursor(0,0);
display.println("Tombol Ditekan!");
display.println("Memanggil...");
display.display();
delay(500); // Penundaan singkat untuk update display
makeCall("+628112508805", 15); // Durasi panggilan 15 detik saat tombol ditekan
display.clearDisplay();
display.setCursor(0,0);
display.println("Panggilan Dipicu.");
display.println("Siap untuk tekan lagi.");
display.display();
}
lastButtonPressTime = millis(); // Rekam waktu penekanan ini
} else if (buttonState == HIGH) {
lastButtonPressTime = 0; // Reset timer debounce jika tombol dilepas
}
}
// Fungsi untuk mengirim perintah AT ke SIM800L dan membaca responsnya
String sendATCommand(String command) {
Serial.print("Mengirim: ");
Serial.println(command);
sim800lSerial.println(command);
String response = "";
long timeout = millis();
while (millis() - timeout < 2000) {
if (sim800lSerial.available()) {
char c = sim800lSerial.read();
Serial.write(c);
response += c;
}
}
Serial.println();
return response;
}
// Fungsi untuk mengontrol status LED berdasarkan hasil "ping"
// Jika pingSuccess TRUE (modul merespons "OK"), LED menyala stabil.
// Jika pingSuccess FALSE (modul tidak merespons "OK" atau timeout), LED berkedip cepat.
void setLedStatus(bool pingSuccess) {
if (pingSuccess) {
digitalWrite(LED_PIN, HIGH); // LED ON (menyala stabil)
Serial.println("LED ON: Modul merespons dengan OK.");
} else {
Serial.println("LED BLINK: Modul tidak merespons OK (timeout atau error).");
for (int i = 0; i < 5; i++) { // Berkedip cepat 5 kali
digitalWrite(LED_PIN, HIGH); // LED menyala
delay(100); // Jeda singkat
digitalWrite(LED_PIN, LOW); // LED mati
delay(100); // Jeda singkat
}
digitalWrite(LED_PIN, LOW); // Pastikan LED mati setelah berkedip
}
}
// Fungsi untuk mendapatkan dan menampilkan kekuatan sinyal (RSSI) di OLED
void getAndDisplaySignalStrength() {
String response = sendATCommand("AT+CSQ");
setLedStatus(response.indexOf("OK") != -1); // Perbarui status LED berdasarkan respons AT+CSQ
int rssi = -1;
int commaIndex = response.indexOf(',');
if (response.indexOf("+CSQ:") != -1 && commaIndex != -1) {
String rssiStr = response.substring(response.indexOf(":") + 1, commaIndex);
rssi = rssiStr.toInt();
}
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.println("Kekuatan Sinyal:");
display.setTextSize(2);
if (rssi >= 0 && rssi <= 31) {
display.print("RSSI: ");
display.print(rssi);
display.print(" (");
display.print(-113 + rssi * 2);
display.println(" dBm)");
display.setTextSize(1);
display.print("Status: ");
if (rssi >= 20) {
display.println("Sangat Baik");
} else if (rssi >= 10) {
display.println("Baik");
} else if (rssi >= 2) {
display.println("Cukup");
} else {
display.println("Lemah/Tidak Ada");
}
} else {
display.println("Tidak Diketahui");
}
display.display();
}
// Fungsi untuk mengirim SMS ke nomor telepon tertentu dengan pesan tertentu
void sendSMS(String phoneNumber, String message) {
Serial.println("Mengatur mode SMS ke Text Mode...");
String modeResponse = sendATCommand("AT+CMGF=1");
setLedStatus(modeResponse.indexOf("OK") != -1);
delay(1000);
Serial.print("Mengirim SMS ke: ");
Serial.println(phoneNumber);
sim800lSerial.print("AT+CMGS=\"");
sim800lSerial.print(phoneNumber);
sim800lSerial.println("\"");
delay(100);
sim800lSerial.print(message);
sim800lSerial.write(0x1A);
Serial.println("Pesan dikirim. Menunggu konfirmasi...");
String smsConfirmation = "";
long timeout = millis();
while (millis() - timeout < 10000) {
if (sim800lSerial.available()) {
char c = sim800lSerial.read();
Serial.write(c);
smsConfirmation += c;
}
}
Serial.println();
setLedStatus(smsConfirmation.indexOf("OK") != -1 || smsConfirmation.indexOf("+CMGS:") != -1);
}
// Fungsi untuk melakukan panggilan telepon ke nomor yang ditentukan
// Panggilan akan otomatis diputus setelah callDurationSeconds
void makeCall(String phoneNumber, int callDurationSeconds) {
Serial.print("Melakukan panggilan ke: ");
Serial.println(phoneNumber);
display.clearDisplay();
display.setCursor(0,0);
display.println("Memanggil:");
display.println(phoneNumber);
display.display();
String callResponse = sendATCommand("ATD" + phoneNumber + ";");
setLedStatus(callResponse.indexOf("OK") != -1);
if (callResponse.indexOf("OK") != -1) {
Serial.println("Panggilan dimulai. Menunggu koneksi atau timeout...");
display.clearDisplay();
display.setCursor(0,0);
display.println("Panggilan Berlangsung...");
display.println(phoneNumber);
display.display();
delay(callDurationSeconds * 1000);
Serial.println("Mengakhiri panggilan...");
display.clearDisplay();
display.setCursor(0,0);
display.println("Mengakhiri Panggilan...");
display.display();
String hangupResponse = sendATCommand("ATH");
setLedStatus(hangupResponse.indexOf("OK") != -1);
delay(1000);
Serial.println("Panggilan diakhiri.");
} else {
Serial.println("Gagal memulai panggilan atau nomor tidak valid.");
display.clearDisplay();
display.setCursor(0,0);
display.println("Panggilan Gagal!");
display.println("Periksa Sinyal/No.");
display.display();
}
}
// Fungsi untuk menghubungkan ESP32 ke WiFi
void connectWiFi() {
Serial.print("Menghubungkan ke WiFi SSID: ");
Serial.println(WIFI_SSID);
display.clearDisplay();
display.setCursor(0, 0);
display.println("Menghubungkan WiFi:");
display.println(WIFI_SSID);
display.display();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) { // Coba 20 kali (sekitar 10 detik)
delay(500);
Serial.print(".");
display.print(".");
display.display();
attempts++;
}
display.clearDisplay();
display.setCursor(0, 0);
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi Terhubung!");
Serial.print("Alamat IP: ");
Serial.println(WiFi.localIP());
display.println("WiFi Terhubung!");
display.print("IP: ");
display.println(WiFi.localIP());
} else {
Serial.println("\nGagal Terhubung ke WiFi!");
display.println("Gagal Terhubung!");
display.println("Cek SSID/Sandi.");
}
display.display();
delay(2000);
}
// Fungsi untuk menguji koneksi ke IP gateway menggunakan koneksi TCP
// Mengembalikan TRUE jika koneksi berhasil (ping reply), FALSE jika gagal (timeout)
bool testGatewayPing() {
IPAddress gatewayIP = WiFi.gatewayIP();
Serial.print("Mencoba koneksi ke Gateway IP: ");
Serial.print(gatewayIP);
Serial.println(" di port 80...");
WiFiClient client;
bool connected = client.connect(gatewayIP, 80); // Coba terhubung ke port 80
if (connected) {
Serial.println("Koneksi Gateway Berhasil.");
client.stop(); // Hentikan koneksi
return true;
} else {
Serial.println("Koneksi Gateway Gagal (Timeout).");
client.stop(); // Hentikan koneksi
return false;
}
}
No comments:
Post a Comment