Search This Blog

Saturday, 28 June 2025

ESP PENGIRIM NOTIFIKASI BERUPA PING IP ADRESS PLUS LCD

 #include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#include <WiFi.h>

#include <WebServer.h>

#include <Preferences.h>

#include <HTTPClient.h>

#include <ESP32Ping.h> // Library untuk fungsi ping


// --- Konfigurasi OLED ---

#define SCREEN_WIDTH 128    // Lebar layar OLED

#define SCREEN_HEIGHT 64    // Tinggi layar OLED

// Inisialisasi objek display OLED

// Alamat I2C default untuk SSD1306 adalah 0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);


// --- Objek & Variabel Global ---

Preferences preferences; // Untuk menyimpan konfigurasi di NVS (Non-Volatile Storage)

WebServer server;        // Objek Web Server

HTTPClient http;         // Objek HTTPClient, diinisialisasi sekali


// --- Variabel Konfigurasi (akan dimuat dari NVS) ---

String ssid = "";            // SSID WiFi

String password = "";        // Password WiFi

String ipStr = "";           // IP statis (opsional)

String gwStr = "";           // Gateway statis (opsional)

String subnetStr = "";       // Subnet statis (opsional)

int serverPort = 80;         // Port web server

String notificationTargetIP = "192.168.1.2"; // IP tujuan untuk notifikasi HTTP GET


// Array untuk 5 IP target yang akan di-ping

IPAddress targetIPs[5];

// Status ping untuk setiap IP

bool pingStatus[5] = {false, false, false, false, false};


// Pesan notifikasi default (dapat diubah melalui web UI)

String msgTarget1Down = "Target IP 1 Down";

String msgTarget2Down = "Target IP 2 Down";

String msgTarget3Down = "Target IP 3 Down";

String msgTarget4Down = "Target IP 4 Down";

String msgTarget5Down = "Target IP 5 Down";


// Flag untuk mencegah pengiriman notifikasi berulang untuk status down

bool target1DownSent = false;

bool target2DownSent = false;

bool target3DownSent = false;

bool target4DownSent = false;

bool target5DownSent = false;


// Variabel untuk interval loop non-blocking

unsigned long previousMillis = 0;

const long pingInterval = 10000; // Cek ping setiap 10 detik


// --- Fungsi URL Encoding ---

// Melakukan URL encoding pada string, terutama mengganti spasi dengan %20

String urlEncode(const String& str) {

  String encodedString = "";

  char c;

  char code0;

  char code1;

  for (int i = 0; i < str.length(); i++) {

    c = str.charAt(i);

    if (c == ' ') { // Ganti spasi dengan %20

      encodedString += "%20";

    } else if (isalnum(c)) { // Karakter alfanumerik tidak perlu di-encode

      encodedString += c;

    } else { // Encode karakter lainnya (minimalis untuk kasus ini)

      code0 = (c & 0xf) + '0';

      if ((c & 0xf) > 9) {

        code0 = (c & 0xf) - 10 + 'A';

      }

      c = (c >> 4) & 0xf;

      code1 = c + '0';

      if (c > 9) {

        code1 = c - 10 + 'A';

      }

      encodedString += '%';

      encodedString += code1;

      encodedString += code0;

    }

  }

  return encodedString;

}


// --- Fungsi Pengiriman Notifikasi ---

// Mengirim notifikasi HTTP GET ke IP target dengan pesan tertentu

void sendNotification(String message) {

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

    String encodedMessage = urlEncode(message);

    String url = "http://" + notificationTargetIP + "/notif?src=" + encodedMessage;


    Serial.print("Mengirim notifikasi: ");

    Serial.println(url);


    http.begin(url);

    int httpCode = http.GET();


    if (httpCode > 0) {

      Serial.printf("[HTTP] GET... code: %d\n", httpCode);

      if (httpCode == HTTP_CODE_OK) {

        String payload = http.getString();

        Serial.println(payload);

      }

    } else {

      Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());

    }

    http.end();

  } else {

    Serial.println("Tidak terhubung ke WiFi, notifikasi tidak terkirim.");

  }

}


// --- Web Server Handlers ---

// Menampilkan halaman web konfigurasi

void handleRoot() {

  String html = "<!DOCTYPE html><html><head><meta charset='UTF-8'>"

                "<meta name='viewport' content='width=device-width, initial-scale=1.0'>"

                "<title>ESP32 Ping Monitor & Notifikasi</title>"

                "<style>"

                "body { font-family: Arial, sans-serif; background:#f9f9f9; margin:0; padding:20px; }"

                ".container { max-width: 600px; margin: auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }"

                "h1, h2 { font-size: 22px; color: #333; }"

                "form label { display: block; margin-top: 10px; font-weight: bold; }"

                "form input[type='text'], form input[type='password'], form input[type='number'] { width: calc(100% - 16px); padding: 8px; margin-top: 5px; border: 1px solid #ccc; border-radius: 5px; }"

                "form input[type='submit'] { background-color: #007bff; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; font-size: 16px; margin-top: 20px; }"

                "form input[type='submit']:hover { background-color: #0056b3; }"

                ".section { margin-top: 30px; border-top: 1px solid #eee; padding-top: 20px; }"

                ".status-box { background-color: #e6f7ff; border: 1px solid #91d5ff; padding: 10px; border-radius: 5px; margin-bottom: 20px; }"

                ".status-box p { margin: 5px 0; }"

                ".ping-status ul { list-style: none; padding: 0; }"

                ".ping-status li { background-color: #f8f9fa; border: 1px solid #e9ecef; padding: 8px; margin-bottom: 5px; border-radius: 4px; }"

                ".ping-status .up { color: #28a745; font-weight: bold; }"

                ".ping-status .down { color: #dc3545; font-weight: bold; }"

                ".ping-status .na { color: gray; font-weight: bold; }"

                "</style></head><body>";


  html += "<div class='container'>";

  html += "<h1>ESP32 Ping Monitor & Notifikasi</h1>";


  // Tampilkan Status Koneksi WiFi

  html += "<div class='status-box'>";

  html += "<h2>Status Koneksi</h2>";

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

    html += "<p><strong>Status:</strong> Terhubung ke WiFi</p>";

    html += "<p><strong>SSID:</strong> " + WiFi.SSID() + "</p>";

    html += "<p><strong>IP Lokal:</strong> " + WiFi.localIP().toString() + "</p>";

  } else {

    html += "<p><strong>Status:</strong> Mode Access Point Aktif</p>";

    html += "<p><strong>SSID AP:</strong> PUTU@TECKNO-ESP32-PING</p>"; // SSID AP baru

    html += "<p><strong>IP AP:</strong> " + WiFi.softAPIP().toString() + "</p>";

    html += "<p><strong>Password AP:</strong> rejeki88</p>";

  }

  html += "<p><strong>Port Web:</strong> " + String(serverPort) + "</p>";

  html += "<p><strong>IP Penerima Notifikasi:</strong> " + notificationTargetIP + "</p>";

  html += "</div>";


  // Tampilkan Status Ping Saat Ini

  html += "<div class='section ping-status'>";

  html += "<h2>Status Ping Terakhir:</h2><ul>";

  IPAddress unsetIP; // Defaultnya 0.0.0.0

  for (int i = 0; i < 5; i++) {

    html += "<li><strong>Target " + String(i + 1) + " (" + targetIPs[i].toString() + "):</strong> ";

    if (targetIPs[i] == unsetIP) {

      html += "<span class='na'>N/A (Tidak Dikonfigurasi)</span></li>";

    } else {

      html += "<span class='" + String(pingStatus[i] ? "up" : "down") + "'>" + String(pingStatus[i] ? "UP" : "DOWN") + "</span></li>";

    }

  }

  html += "</ul></div>";



  html += "<form action='/save' method='post'>";

  html += "<div class='section'><h2>Pengaturan WiFi</h2>";

  html += "<label for='ssid'>SSID WiFi:</label><input type='text' name='ssid' value='" + ssid + "'><br>";

  html += "<label for='password'>Password WiFi:</label><input type='password' name='password' value='" + password + "'><br>";

  html += "</div>";


  html += "<div class='section'><h2>Pengaturan Jaringan Statis (Opsional)</h2>";

  html += "<label for='ip'>IP Address (kosongkan untuk DHCP):</label><input type='text' name='ip' value='" + ipStr + "'><br>";

  html += "<label for='gw'>Gateway:</label><input type='text' name='gw' value='" + gwStr + "'><br>";

  html += "<label for='subnet'>Subnet Mask:</label><input type='text' name='subnet' value='" + subnetStr + "'><br>";

  html += "</div>";


  html += "<div class='section'><h2>Pengaturan Monitoring & Notifikasi</h2>";

  html += "<label for='port'>Port Web Server:</label><input type='number' name='port' value='" + String(serverPort) + "'><br>";

  html += "<label for='notification_target_ip'>IP Penerima Notifikasi (misal: 192.168.1.100):</label><input type='text' name='notification_target_ip' value='" + notificationTargetIP + "'><br>";


  html += "<h3>Alamat IP Target Ping (hingga 5):</h3>";

  for (int i = 0; i < 5; i++) {

    html += "<label for='target_ip_" + String(i) + "'>Target IP " + String(i + 1) + ":</label><input type='text' name='target_ip_" + String(i) + "' value='" + targetIPs[i].toString() + "'><br>";

  }

  html += "</div>";


  html += "<div class='section'><h2>Pesan Notifikasi Kustom (IP Down)</h2>";

  html += "<label for='msg_target1'>Pesan Target IP 1 Down:</label><input type='text' name='msg_target1' value='" + msgTarget1Down + "'><br>";

  html += "<label for='msg_target2'>Pesan Target IP 2 Down:</label><input type='text' name='msg_target2' value='" + msgTarget2Down + "'><br>";

  html += "<label for='msg_target3'>Pesan Target IP 3 Down:</label><input type='text' name='msg_target3' value='" + msgTarget3Down + "'><br>";

  html += "<label for='msg_target4'>Pesan Target IP 4 Down:</label><input type='text' name='msg_target4' value='" + msgTarget4Down + "'><br>";

  html += "<label for='msg_target5'>Pesan Target IP 5 Down:</label><input type='text' name='msg_target5' value='" + msgTarget5Down + "'><br>";

  html += "</div>";


  html += "<input type='submit' value='Simpan Pengaturan & Restart'></form>";

  html += "</div></body></html>";


  server.send(200, "text/html", html);

}


// Menyimpan konfigurasi dari form

void handleSave() {

  // Simpan pengaturan WiFi

  ssid = server.arg("ssid");

  password = server.arg("password");

  ipStr = server.arg("ip");

  gwStr = server.arg("gw");

  subnetStr = server.arg("subnet");

  serverPort = server.arg("port").toInt();

  notificationTargetIP = server.arg("notification_target_ip");


  // Simpan IP Target Ping

  for (int i = 0; i < 5; i++) {

    String argName = "target_ip_" + String(i);

    if (server.hasArg(argName)) {

      targetIPs[i].fromString(server.arg(argName));

    }

  }


  // Simpan pesan notifikasi kustom

  msgTarget1Down = server.arg("msg_target1");

  msgTarget2Down = server.arg("msg_target2");

  msgTarget3Down = server.arg("msg_target3");

  msgTarget4Down = server.arg("msg_target4");

  msgTarget5Down = server.arg("msg_target5");


  preferences.begin("ping_monitor", false); // Buka NVS dalam mode baca/tulis

  preferences.putString("ssid", ssid);

  preferences.putString("password", password);

  preferences.putString("ip", ipStr);

  preferences.putString("gw", gwStr);

  preferences.putString("subnet", subnetStr);

  preferences.putInt("port", serverPort);

  preferences.putString("notifTargetIP", notificationTargetIP);


  for (int i = 0; i < 5; i++) {

    String key = "targetIP" + String(i);

    preferences.putString(key.c_str(), targetIPs[i].toString());

  }


  preferences.putString("msgT1", msgTarget1Down);

  preferences.putString("msgT2", msgTarget2Down);

  preferences.putString("msgT3", msgTarget3Down);

  preferences.putString("msgT4", msgTarget4Down);

  preferences.putString("msgT5", msgTarget5Down);

  preferences.end(); // Tutup NVS


  server.send(200, "text/html", "<html><body><h1>Pengaturan Tersimpan! Restarting...</h1><p>Mohon tunggu beberapa saat.</p></body></html>");

  delay(2000);

  ESP.restart(); // Restart ESP32 untuk menerapkan pengaturan baru

}


// Memuat pengaturan dari NVS dan menginisialisasi WiFi

void setupWiFi() {

  preferences.begin("ping_monitor", true); // Buka NVS dalam mode baca saja

  ssid = preferences.getString("ssid", "");

  password = preferences.getString("password", "");

  ipStr = preferences.getString("ip", "");

  gwStr = preferences.getString("gw", "");

  subnetStr = preferences.getString("subnet", "");

  serverPort = preferences.getInt("port", 80);

  notificationTargetIP = preferences.getString("notifTargetIP", "192.168.1.2"); // Default IP penerima


  // Muat IP Target Ping

  IPAddress unsetIP; // 0.0.0.0

  for (int i = 0; i < 5; i++) {

    String key = "targetIP" + String(i);

    String ipString = preferences.getString(key.c_str(), "");

    if (!targetIPs[i].fromString(ipString)) {

      targetIPs[i] = unsetIP; // Jika gagal parsing atau kosong, set ke 0.0.0.0

    }

  }


  // Muat pesan notifikasi kustom

  msgTarget1Down = preferences.getString("msgT1", "Target IP 1 Down");

  msgTarget2Down = preferences.getString("msgT2", "Target IP 2 Down");

  msgTarget3Down = preferences.getString("msgT3", "Target IP 3 Down");

  msgTarget4Down = preferences.getString("msgT4", "Target IP 4 Down");

  msgTarget5Down = preferences.getString("msgT5", "Target IP 5 Down");

  preferences.end(); // Tutup NVS


  if (ssid != "") {

    Serial.print("Mencoba menyambungkan ke WiFi: ");

    Serial.println(ssid);

    if (ipStr != "" && gwStr != "" && subnetStr != "") {

      IPAddress ip, gw, sn;

      if (ip.fromString(ipStr) && gw.fromString(gwStr) && sn.fromString(subnetStr)) {

        WiFi.config(ip, gw, sn);

        Serial.println("Menggunakan IP Statis.");

      } else {

        Serial.println("Konfigurasi IP statis tidak valid. Menggunakan DHCP.");

        // Bersihkan string IP statis agar kembali ke DHCP

        ipStr = "";

        gwStr = "";

        subnetStr = "";

      }

    } else {

      Serial.println("Tidak ada konfigurasi IP statis. Menggunakan DHCP.");

    }


    WiFi.begin(ssid.c_str(), password.c_str());

    int attempts = 0;

    while (WiFi.status() != WL_CONNECTED && attempts < 20) { // Coba 10 detik (20 * 500ms)

      delay(500);

      Serial.print(".");

      if (attempts == 10) { // Coba ulang WiFi.begin jika terlalu lama

        Serial.println("\nMencoba koneksi ulang WiFi...");

        WiFi.disconnect();

        WiFi.reconnect();

      }

      attempts++;

    }

    Serial.println();


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

      Serial.println("WiFi Tersambung!");

      Serial.print("IP Address: ");

      Serial.println(WiFi.localIP());

    } else {

      Serial.println("Gagal terhubung ke WiFi yang dikonfigurasi.");

    }

  } else {

    Serial.println("Tidak ada SSID tersimpan. Memulai mode Access Point.");

  }


  // Jika tidak terhubung ke WiFi atau tidak ada SSID tersimpan, mulai AP

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

    WiFi.mode(WIFI_AP);

    WiFi.softAP("PUTU@TECKNO-ESP32-PING", "rejeki88"); // SSID & Pass untuk AP

    Serial.print("AP Mode Aktif. IP: ");

    Serial.println(WiFi.softAPIP());

    Serial.print("AP Password: ");

    Serial.println("rejeki88");

  }


  server.on("/", HTTP_GET, handleRoot);

  server.on("/save", HTTP_POST, handleSave);

  server.begin(serverPort);

  Serial.print("Web server dimulai pada port: ");

  Serial.println(serverPort);

}


// --- Setup Awal ---

void setup() {

  Serial.begin(115200); // Inisialisasi Serial Monitor

  // Tidak ada pin ADC yang digunakan di sini, jadi tidak perlu analogReadResolution


  // Inisialisasi OLED

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // 0x3C adalah alamat I2C umum

    Serial.println(F("OLED tidak ditemukan atau gagal inisialisasi!"));

    while (true); // Berhenti jika OLED tidak terdeteksi

  }

  display.clearDisplay();

  display.setTextColor(WHITE);

  display.setTextSize(1);

  display.setCursor(10, 10);

  display.println("ESP32 Ping Monitor");

  display.println("PUTU-TECKNO");

  display.display();

  delay(2000); // Tampilkan pesan startup sebentar


  setupWiFi(); // Konfigurasi WiFi dan Web Server

}


// --- Loop Utama ---

void loop() {

  unsigned long currentMillis = millis();


  // Melakukan ping setiap pingInterval (non-blocking)

  if (currentMillis - previousMillis >= pingInterval) {

    previousMillis = currentMillis; // Simpan waktu terakhir


    Serial.println("Melakukan Ping ke Target IP...");

    IPAddress unsetIP; // 0.0.0.0

    for (int i = 0; i < 5; i++) {

      if (targetIPs[i] != unsetIP) { // Hanya ping IP yang valid (bukan 0.0.0.0)

        pingStatus[i] = Ping.ping(targetIPs[i]);

        Serial.printf("Ping ke %s: %s\n", targetIPs[i].toString().c_str(), pingStatus[i] ? "UP" : "DOWN");


        // Kirim notifikasi jika terhubung ke WiFi dan IP down

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

          if (!pingStatus[i]) { // Jika IP DOWN

            // Periksa flag notifikasi untuk IP ini

            bool *sentFlag = nullptr;

            String *msg = nullptr;

            switch (i) {

              case 0: sentFlag = &target1DownSent; msg = &msgTarget1Down; break;

              case 1: sentFlag = &target2DownSent; msg = &msgTarget2Down; break;

              case 2: sentFlag = &target3DownSent; msg = &msgTarget3Down; break;

              case 3: sentFlag = &target4DownSent; msg = &msgTarget4Down; break;

              case 4: sentFlag = &target5DownSent; msg = &msgTarget5Down; break;

            }


            if (sentFlag && msg && !(*sentFlag)) {

              sendNotification(*msg);

              *sentFlag = true;

            }

          } else { // Jika IP UP kembali

            // Reset flag notifikasi untuk IP ini

            bool *sentFlag = nullptr;

            switch (i) {

              case 0: sentFlag = &target1DownSent; break;

              case 1: sentFlag = &target2DownSent; break;

              case 2: sentFlag = &target3DownSent; break;

              case 3: sentFlag = &target4DownSent; break;

              case 4: sentFlag = &target5DownSent; break;

            }

            if (sentFlag) {

              *sentFlag = false; // IP kembali UP, reset flag agar bisa notifikasi lagi jika down

            }

          }

        }

      } else {

        pingStatus[i] = true; // Anggap "UP" jika IP tidak dikonfigurasi, agar tidak ada notifikasi palsu

        Serial.printf("Target IP %d: N/A (Tidak Dikonfigurasi)\n", i+1);

      }

    }

    updateDisplay(); // Perbarui tampilan OLED setelah ping

  }


  server.handleClient(); // Tangani permintaan web server (harus selalu ada di loop)

}


// --- Fungsi OLED Display ---

void updateDisplay() {

  display.clearDisplay();

  display.setTextSize(1);

  display.setTextColor(SSD1306_WHITE);

  display.setCursor(0, 0);


  // Tampilkan status WiFi di baris paling atas

  display.print("WiFi: ");

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

    display.print("Connected");

  } else {

    display.print("AP Mode");

  }

  display.println(); // Pindah ke baris berikutnya


  // Tampilkan IP Address saat ini

  display.print("IP: ");

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

    display.println(WiFi.localIP().toString());

  } else {

    display.println(WiFi.softAPIP().toString());

  }


  display.println("--- Ping Status ---");

  IPAddress unsetIP; // 0.0.0.0

  for (int i = 0; i < 5; i++) {

    display.print("T"); display.print(i + 1); display.print(": ");

    if (targetIPs[i] == unsetIP) { // Jika IP tidak dikonfigurasi

      display.println("N/A");

    } else {

      display.setTextColor(pingStatus[i] ? SSD1306_WHITE : SSD1306_INVERSE); // Warna terbalik jika DOWN

      display.println(pingStatus[i] ? "UP" : "DOWN");

      display.setTextColor(SSD1306_WHITE); // Kembalikan warna normal

    }

  }

  display.display();

}

No comments:

Post a Comment

CARGER AKI CONTROLER INA226-LIBARY WE ROTARI SW+OLED 0.96 SUKSES TAMPILAN LEBIH BAIK

 #include <Wire.h>  #include <Adafruit_GFX.h>    // Library grafis Adafruit #include <Adafruit_SSD1306.h> // Library untuk...