Search This Blog

Monday, 16 June 2025

ESP32-SIM800L-OLED-128*64-WIFI-DHCP-PING-GOOGLE.COM-PIN2-LAMPU-SINYAL-PIN4-CALL

 #include <HardwareSerial.h>

#include <Wire.h> // Untuk komunikasi I2C OLED

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#include <WiFi.h> // Library untuk konektivitas WiFi

#include <WiFiClient.h> // Untuk melakukan koneksi TCP sebagai "ping"


// Definisi 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


// Definisi pin untuk LED indikator

#define LED_PIN 2 // Contoh pin GPIO2 untuk LED


// Definisi pin untuk tombol fisik

#define BUTTON_PIN 4 // Contoh pin GPIO4 untuk tombol

                     // Hubungkan satu sisi tombol ke pin ini, dan sisi lain ke GND.

                     // Resistor pull-up internal akan diaktifkan.


// Dimensi 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"; // Nama WiFi

const char* WIFI_PASSWORD = "rejeki88"; // Kata sandi WiFi


// Deklarasi objek SSD1306 (alamat I2C OLED 0x3C atau 0x3D)

// Ubah 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 debugging Serial)


// Variabel global untuk target ping (sekarang hostname)

String pingTargetHostname = "google.com"; // Target ping ke google.com


// Variabel global untuk menyimpan kekuatan sinyal GSM

int gsmSignalRSSI = -1; // -1 menunjukkan tidak diketahui atau tidak ada sinyal


// --- Deklarasi Prototype Fungsi ---

String sendATCommand(String command);

String sendATCommand(String command, unsigned long timeoutMs); // Overloaded untuk timeout kustom

void getAndDisplaySignalStrength();

void sendSMS(String phoneNumber, String message);

void setLedStatus(bool pingSuccess);

void makeCall(String phoneNumber, int callDurationSeconds);

void connectWiFi(); // Fungsi untuk terhubung ke WiFi

bool testPingTarget(); // Fungsi untuk menguji ping ke target dinamis (hostname)

void updateOLEDMainStatus(); // Fungsi untuk memperbarui tampilan status utama


// Variabel untuk debouncing tombol

long lastButtonPressTime = 0; // Waktu terakhir tombol ditekan

const long debounceDelay = 50; // Waktu debounce dalam milidetik


// Variabel global untuk status ping dan berkedip

String pingStatusMessage = "Menunggu..."; // Pesan status ping untuk ditampilkan di OLED

bool showPingStatusBlink = true; // Flag untuk mengontrol kedipan global

unsigned long lastPingStatusBlinkToggle = 0; // Waktu terakhir status ping di-toggle

const unsigned long pingStatusBlinkInterval = 500; // Interval kedipan 500ms


void setup() {

  // Inisialisasi komunikasi serial untuk debugging (serial monitor)

  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 saat inisialisasi


  // Inisialisasi pin tombol sebagai input dengan resistor pull-up internal

  // Tombol harus dihubungkan 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(); // Perbarui kekuatan sinyal sekarang

  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);


  // --- Koneksi WiFi Awal ---

  connectWiFi(); // Lakukan koneksi WiFi saat startup


  // Pesan pengujian akhir di OLED

  updateOLEDMainStatus(); // Perbarui tampilan status utama setelah inisialisasi

}


void loop() {

  // Logika 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(); // Perbarui kekuatan sinyal di OLED dan LED

  }


  // --- Logika Koneksi WiFi dan Ping Target ---

  static unsigned long lastTargetPingTime = 0;

  static unsigned long targetPingInterval = 30000; // Periksa target setiap 30 detik


  static bool emergencyActionInitiated = false;

  static unsigned long lastEmergencyActionTime = 0;

  const unsigned long emergencyActionCooldown = 5 * 60 * 1000; // Cooldown 5 menit untuk tindakan darurat (SMS & Panggilan)


  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) {

    // Periksa Ping Target

    if (millis() - lastTargetPingTime >= targetPingInterval) {

      lastTargetPingTime = millis();

      Serial.print("Melakukan Uji Ping ");

      Serial.print(pingTargetHostname);

      Serial.println(" (Port 80)..."); // Port 80 untuk pengujian konektivitas umum

      if (testPingTarget()) { // Jika ping berhasil

        Serial.print("Ping ");

        Serial.print(pingTargetHostname);

        Serial.println(" (Port 80) Berhasil (koneksi WiFi baik).");

        pingStatusMessage = "Ping " + pingTargetHostname + ": OK"; // Update status text

        emergencyActionInitiated = false; // Setel ulang flag tindakan darurat jika target dapat dijangkau

      } else { // Jika ping timeout

        Serial.print("Ping ");

        Serial.print(pingTargetHostname);

        Serial.println(" (Port 80) Timeout! Memulai aksi darurat...");

        pingStatusMessage = "Ping " + pingTargetHostname + ": PUTUS"; // Perbarui teks status

        // Picu tindakan darurat (SMS & Panggilan) jika ping gagal

        if (!emergencyActionInitiated || (millis() - lastEmergencyActionTime >= emergencyActionCooldown)) {

          Serial.println("Mengirim SMS: KONEKSI INTERNET PUTUS (" + pingTargetHostname + " GAGAL)");

          sendSMS("+628112508805", "KONEKSI INTERNET PUTUS (" + pingTargetHostname + " GAGAL)"); // Kirim SMS

          delay(2000); // Penundaan singkat sebelum panggilan

          makeCall("+628112508805", 15); // Lakukan panggilan 15 detik


          emergencyActionInitiated = true;

          lastEmergencyActionTime = millis();

        } else {

          Serial.println("Aksi darurat (SMS/Panggilan) telah dipicu baru-baru ini karena kegagalan ping. Menunggu cooldown...");

        }

      }

      updateOLEDMainStatus(); // Perbarui tampilan setelah ping target

    }

  }


  // --- Logika Pengecekan Tombol ---

  int buttonState = digitalRead(BUTTON_PIN);


  if (buttonState == LOW && (millis() - lastButtonPressTime) > debounceDelay) {

    if (lastButtonPressTime == 0) { // Hanya picu jika ini adalah 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 pembaruan tampilan


      makeCall("+628112508805", 15); // Durasi panggilan 15 detik saat tombol ditekan


      updateOLEDMainStatus(); // Perbarui tampilan setelah panggilan selesai

    }

    lastButtonPressTime = millis(); // Catat waktu penekanan ini

  } else if (buttonState == HIGH) {

      lastButtonPressTime = 0; // Setel ulang timer debounce jika tombol dilepaskan

  }


  // --- Tampilkan Status Ping di Baris Bawah OLED (Berkedip) ---

  if (millis() - lastPingStatusBlinkToggle >= pingStatusBlinkInterval) {

    lastPingStatusBlinkToggle = millis();

    showPingStatusBlink = !showPingStatusBlink; // Toggle visibilitas


    // Panggil fungsi untuk memperbarui seluruh tampilan status utama, termasuk baris berkedip

    updateOLEDMainStatus();

  }

}


// Fungsi untuk mengirim perintah AT ke SIM800L dan membaca responsnya dengan timeout default

String sendATCommand(String command) {

  return sendATCommand(command, 2000); // Timeout default 2 detik

}


// Fungsi untuk mengirim perintah AT ke SIM800L dan membaca responsnya dengan timeout kustom

String sendATCommand(String command, unsigned long timeoutMs) {

  Serial.print("Mengirim: ");

  Serial.println(command);

  sim800lSerial.println(command);


  String response = "";

  unsigned long timeout = millis();

  while (millis() - timeout < timeoutMs) {

    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 tetap menyala.

// Jika pingSuccess FALSE (modul tidak merespons "OK" atau timeout), LED berkedip cepat.

void setLedStatus(bool pingSuccess) {

  if (pingSuccess) {

    digitalWrite(LED_PIN, HIGH); // LED ON (stabil menyala)

  } else {

    for (int i = 0; i < 2; i++) { // Berkedip cepat 2 kali untuk menunjukkan masalah

      digitalWrite(LED_PIN, HIGH); // LED menyala

      delay(50); // Penundaan singkat

      digitalWrite(LED_PIN, LOW); // LED mati

      delay(50); // Penundaan singkat

    }

    digitalWrite(LED_PIN, LOW); // Pastikan LED mati setelah berkedip

  }

}


// Fungsi untuk mendapatkan dan menampilkan kekuatan sinyal (RSSI)

void getAndDisplaySignalStrength() {

  String response = sendATCommand("AT+CSQ");

  setLedStatus(response.indexOf("OK") != -1); // Perbarui status LED berdasarkan respons AT+CSQ


  int tempRssi = -1;

  int commaIndex = response.indexOf(',');

  if (response.indexOf("+CSQ:") != -1 && commaIndex != -1) {

    String rssiStr = response.substring(response.indexOf(":") + 1, commaIndex);

    tempRssi = rssiStr.toInt();

  }

  gsmSignalRSSI = tempRssi; // Simpan dalam variabel global

  Serial.print("Sinyal GSM RSSI: ");

  Serial.println(gsmSignalRSSI);

}


// 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(100); // Beri modul sedikit waktu


  Serial.print("Mengirim SMS ke: ");

  Serial.println(phoneNumber);

  Serial.print("Pesan: ");

  Serial.println(message);


  sim800lSerial.print("AT+CMGS=\"");

  sim800lSerial.print(phoneNumber);

  sim800lSerial.println("\"");

  delay(100); // Penundaan kecil sebelum mengirim konten pesan


  sim800lSerial.print(message);

  sim800lSerial.write(0x1A); // Ctrl+Z untuk mengirim SMS

  Serial.println("Pesan dikirim. Menunggu konfirmasi...");


  String smsConfirmation = sendATCommand("", 10000); // Tunggu hingga 10 detik untuk konfirmasi

  setLedStatus(smsConfirmation.indexOf("OK") != -1 || smsConfirmation.indexOf("+CMGS:") != -1);

  if (smsConfirmation.indexOf("OK") != -1 || smsConfirmation.indexOf("+CMGS:") != -1) {

    Serial.println("SMS berhasil dikirim.");

  } else {

    Serial.println("Gagal mengirim SMS atau tidak ada konfirmasi.");

  }

}


// Fungsi untuk melakukan panggilan telepon ke nomor yang ditentukan

// Panggilan akan otomatis terputus setelah callDurationSeconds

void makeCall(String phoneNumber, int callDurationSeconds) {

  Serial.print("Melakukan panggilan ke: ");

  Serial.println(phoneNumber);

  display.clearDisplay(); // Hapus seluruh tampilan selama panggilan

  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(); // Hapus lagi untuk status

    display.setCursor(0,0);

    display.println("Panggilan Berlangsung...");

    display.println(phoneNumber);

    display.display();


    delay(callDurationSeconds * 1000);


    Serial.println("Mengakhiri panggilan...");

    display.clearDisplay(); // Hapus lagi

    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(); // Hapus lagi

    display.setCursor(0,0);

    display.println("Panggilan Gagal!");

    display.println("Periksa Sinyal/No.");

    display.display();

  }

  // Setelah panggilan, panggil updateOLEDMainStatus untuk memperbarui tampilan utama

  updateOLEDMainStatus();

}


// 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();


  // Menggunakan DHCP secara default dengan WiFi.begin()

  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()); // Tampilkan Alamat IP yang diperoleh

    display.print("GW: ");

    display.println(WiFi.gatewayIP()); // Tampilkan IP Gateway

    pingStatusMessage = "Menunggu..."; // Reset status ping

  } else {

    Serial.println("\nGagal Terhubung ke WiFi!");

    display.println("Gagal Terhubung!");

    display.println("Cek SSID/Sandi.");

    pingStatusMessage = "WiFi PUTUS"; // Atur status ping jika WiFi gagal

  }

  display.display();

  delay(2000);

}


// Fungsi untuk menguji koneksi ke target ping (hostname) pada port 80

bool testPingTarget() {

  IPAddress resolvedIP;

  // Menggunakan WiFi.hostByName untuk menyelesaikan hostname ke alamat IP

  int n = WiFi.hostByName(pingTargetHostname.c_str(), resolvedIP);


  if (n == 0) { // hostByName mengembalikan 0 jika gagal

    Serial.print("ERROR: Gagal menyelesaikan hostname ");

    Serial.print(pingTargetHostname);

    Serial.println("!");

    return false;

  }


  Serial.print("Mencoba koneksi ke ");

  Serial.print(pingTargetHostname);

  Serial.print(" (");

  Serial.print(resolvedIP);

  Serial.println(") (Port 80)..."); // Port 80 untuk pengujian konektivitas umum


  WiFiClient client;

  client.setTimeout(3000); // Atur timeout koneksi ke 3 detik

  bool connected = client.connect(resolvedIP, 80); // Coba terhubung ke port 80


  if (connected) {

    Serial.print("Koneksi ");

    Serial.print(pingTargetHostname);

    Serial.print(" (");

    Serial.print(resolvedIP);

    Serial.println(") (Port 80) Berhasil.");

    client.stop();

    return true;

  } else {

    Serial.print("Koneksi ");

    Serial.print(pingTargetHostname);

    Serial.print(" (");

    Serial.print(resolvedIP);

    Serial.println(") (Port 80) Gagal (Timeout).");

    client.stop();

    return false;

  }

}


// Fungsi untuk memperbarui tampilan status utama di OLED

// Ini akan dipanggil secara berkala dan setelah peristiwa penting

void updateOLEDMainStatus() {

  display.clearDisplay(); // Hapus seluruh tampilan

  display.setTextSize(1);

  display.setTextColor(SSD1306_WHITE);


  // Tampilkan IP lokal dan status WiFi

  display.setCursor(0, 0);

  if (WiFi.status() == WL_CONNECTED) {

    display.println("WiFi Connected!");

    display.print("IP: ");

    display.println(WiFi.localIP());

    display.print("GW: "); // Tampilkan IP Gateway di baris terpisah

    display.println(WiFi.gatewayIP());

  } else {

    display.println("WiFi Disconnected!");

    display.println("Coba Koneksi Lagi...");

  }


  // Tampilkan status sinyal GSM

  display.setCursor(0, 4 * 8); // Mulai setelah 4 baris teks awal (sekitar y=32)

  if (gsmSignalRSSI != -1) {

    display.print("GSM Signal: ");

    display.print(gsmSignalRSSI);

    display.println(" dBm"); // Tampilkan nilai RSSI

  } else {

    display.println("GSM Signal: N/A");

  }


  // Tampilkan status ping target di baris paling bawah

  display.setCursor(0, SCREEN_HEIGHT - 8); // Baris paling bawah (8 piksel dari bawah)

  if (showPingStatusBlink) {

    display.println(pingStatusMessage);

  } else {

    display.println(""); // Biarkan kosong untuk efek kedip

  }


  display.display(); // Tampilkan semua perubahan

}


No comments:

Post a Comment

Tandon Air Otomatis (ESP32 Master & Display) + Kode Lengkap

  Panduan Lengkap Tandon Air Otomatis (ESP32 Master & Display) + Kode Lengkap Diperbarui: 09 August 2025 Artikel ini memandu Anda memban...