Gộp 2 code Duck DDNS và check port trên ESP32

Gộp 2 code Duck DDNS và check port trên ESP32

Gộp 2 code Duck DDNS và check port trên ESP32.

Việc dùng ESP32 làm  việc check port mà mỗi lần cần lấy ippublic thì khá mất công chưa kể nó còn thay đổi. Nên ta sẽ kết hợp với DuckDDns để có tên miền để sử dụng khi check port. Mặc dù biết là hơi tham trên phần cứng ít ỏi của ESP32 nhưng dẫu sao nó vẫn hoạt động tốt nếu chỉ sử dụng với nhu cầu cá nhân.
1Screenshot 2024 06 16 142606

Đoạn code thực thi chức năng sau:

Kết nối Wi-Fi: Thiết lập và duy trì kết nối Wi-Fi với mạng cục bộ, thử lại kết nối nếu cần thiết.

Điều khiển đèn LED: Quản lý việc bật/tắt đèn LED.

Cập nhật DDNS: Tự động cập nhật địa chỉ IP động lên DuckDNS để duy trì kết nối từ xa.

Kiểm tra cổng: Cho phép người dùng kiểm tra trạng thái của các cổng trên một địa chỉ IP hoặc tên miền.

Khởi động lại thiết bị: Thực hiện khởi động lại ESP32 định kỳ để giữ cho thiết bị hoạt động ổn định.

 

Mỗi chức năng trong đoạn code đảm bảo thiết bị ESP32 cập nhật DDNS để duy trì kết nối từ xa và cho phép người dùng kiểm tra trạng thái của các cổng trên một địa chỉ IP hoặc tên miền từ xa nếu mở port cho ESP32.

#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <RTClib.h>

const char* ssid = "mixxxxx";
const char* password = "1234567999";
const char* duckDNS_domain = "subdomain4";
const char* duckDNS_token = "xxx0bd9-ef52-4846-bd17-xxxxxxxx";
const int ledPin = 15; 
const int MAX_CONNECTION_ATTEMPTS = 3;
const int WIFI_RETRY_INTERVAL = 7000; 
const int DDNS_UPDATE_INTERVAL = 60000;
const unsigned long LIGHT_CYCLE_DURATION = 500;
const unsigned long LIGHT_ON_DURATION = 500; 
const unsigned long RESTART_INTERVAL = 43200000; 
bool isWifiConnected = false;
bool isAttemptingConnection = false;
int wifiConnectionAttempts = 0;
unsigned long lastCycleTime = 0;
unsigned long lastDDNSUpdateTime = 0;
unsigned long lastRestartTime = 0;

WebServer server(81);

const char* htmlPage = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
  <title>ESP32 Port Checker</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      background-color: #f0f0f0;
      margin: 0;
      padding: 0;
    }
    h2 {
      color: #333;
    }
    form {
      background: #fff;
      padding: 20px;
      border-radius: 5px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      display: inline-block;
      margin-top: 50px;
    }
    label {
      display: block;
      margin-bottom: 8px;
      color: #555;
    }
    input[type="text"] {
      width: calc(100% - 22px);
      padding: 10px;
      margin-bottom: 20px;
      border: 1px solid #ddd;
      border-radius: 3px;
    }
    input[type="submit"] {
      padding: 10px 20px;
      border: none;
      background-color: #007bff;
      color: white;
      border-radius: 3px;
      cursor: pointer;
    }
    input[type="submit"]:hover {
      background-color: #0056b3;
    }
  </style>
  <script>
    async function fetchPublicIP() {
      const response = await fetch('https://api.ipify.org?format=json');
      const data = await response.json();
      document.getElementById('ip').value = data.ip;
    }
    window.onload = fetchPublicIP;
  </script>
</head>
<body>
  <h2>ESP32 Port Checker</h2>
  <form action="/check" method="get">
    <label for="ip">IP/Domain:</label>
    <input type="text" id="ip" name="ip"><br>
    <label for="port">Ports (separated by space):</label>
    <input type="text" id="port" name="port"><br>
    <input type="submit" value="Check">
  </form>
  %s
</body>
</html>
)rawliteral";

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT); 
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  digitalWrite(ledPin, HIGH);

  server.on("/", HTTP_GET, []() {
    server.send(200, "text/html", htmlPage);
  });

  server.on("/check", HTTP_GET, []() {
    if (server.hasArg("ip") && server.hasArg("port")) {
      String ip = server.arg("ip");
      String ports = server.arg("port");
      String result = "<p>Checking " + ip + " - ";

      int start = 0;
      int end = ports.indexOf(' ');
      while (end != -1) {
        String portStr = ports.substring(start, end);
        int port = portStr.toInt();
        bool isOpen = checkPort(ip, port);
        result += "Port " + portStr + " is " + (isOpen ? "Open" : "Closed") + ". ";
        start = end + 1;
        end = ports.indexOf(' ', start);
      }
      String portStr = ports.substring(start);
      int port = portStr.toInt();
      bool isOpen = checkPort(ip, port);
      result += "Port " + portStr + " is " + (isOpen ? "Open" : "Closed") + ". ";

      result += "</p>";
      server.send(200, "text/html", String(htmlPage) + result);
    } else {
      server.send(200, "text/html", String(htmlPage) + "<p>Invalid input</p>");
    }
  });

  server.begin();

  lastRestartTime = millis(); 
  updateDDNS();
}

void loop() {
  server.handleClient();
  checkWifiConnection();
  controlLED();
    if (millis() - lastRestartTime >= RESTART_INTERVAL) {
    restartESP32();
  }
    if (isWifiConnected && millis() - lastDDNSUpdateTime >= DDNS_UPDATE_INTERVAL) {
    updateDDNS();
    lastDDNSUpdateTime = millis();
  }
}


bool checkPort(String host, uint16_t port) {
  WiFiClient client;
  bool connected = client.connect(host.c_str(), port);
  client.stop(); 
  return connected;
}

void controlLED() {
  unsigned long currentMillis = millis();


  if (isWifiConnected && (currentMillis - lastCycleTime >= LIGHT_CYCLE_DURATION)) {
    lastCycleTime = currentMillis;
    // Nếu có kết nối WiFi, sáng LED và bỏ qua điều kiện chớp tắt ban đầu
    digitalWrite(ledPin, HIGH);
    return;
  }

  if (currentMillis - lastCycleTime >= LIGHT_ON_DURATION) {
    digitalWrite(ledPin, LOW);
  } else {
    digitalWrite(ledPin, HIGH); 
  }
}

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

    isWifiConnected = false;
    if (!isAttemptingConnection) {
      isAttemptingConnection = true;
      wifiConnectionAttempts = 0;
    }

    if (isAttemptingConnection && wifiConnectionAttempts < MAX_CONNECTION_ATTEMPTS) {
      if (millis() - lastCycleTime >= WIFI_RETRY_INTERVAL) {
        wifiConnectionAttempts++;
        Serial.print("Attempting to reconnect to WiFi (Attempt ");
        Serial.print(wifiConnectionAttempts);
        Serial.println(")");
        WiFi.begin(ssid, password);
        lastCycleTime = millis();
      }
    } else {
      isAttemptingConnection = false;
      Serial.println("WiFi connection failed after multiple attempts.");
      digitalWrite(ledPin, LOW); 
    }
  } else {
    isWifiConnected = true;
    isAttemptingConnection = false;
    wifiConnectionAttempts = 0; 
    updateDDNS();
  }
}

void updateDDNS() {
  String duckDNS_update_url = "http://www.duckdns.org/update?domains=" + String(duckDNS_domain) + "&token=" + String(duckDNS_token) + "&ip=";
  HTTPClient http;
  http.begin("https://ipv4.icanhazip.com");
  int httpCode = http.GET();
  String currentIP = "";
  if (httpCode == HTTP_CODE_OK) {
    currentIP = http.getString();
    Serial.println("Current IP: " + currentIP);
    HTTPClient httpUpdate;
    httpUpdate.begin(duckDNS_update_url + currentIP);
    int httpUpdateCode = httpUpdate.GET();
    if (httpUpdateCode == HTTP_CODE_OK) {
      Serial.println("DDNS update success");
    }
    httpUpdate.end();
  } else {
    Serial.println("Failed to connect to IP service");
  }
  http.end();
}

void restartESP32() {
  Serial.println("Restarting ESP32...");
  ESP.restart();
}

 

Trong code  tôi có hơi tham khi cho kiểm tra nhiều cổng 1 lúc sẽ ảnh hưởng tới tốc độ xử lý và trả về kết quả của ESP32 là chậm một chút. Nhưng nếu bạn chỉ kiểm tra 1 cổng thì vẫn khá nhanh và vì giới hạn phần cứng nên khuyên bạn chỉ nên sài với nhu cầu cá nhân.

Hãy thay đổi 1 số thông tin sau trong code cho phù hợp với bạn.

  const char* ssid = “xxxx”; //tên wifi của bạn
  const char* password = “passwd”; //mật khẩu wifi
  WebServer server(81); // đang port 81 đổi thành port khác nếu cần
  const char* duckDNS_domain = “subdomain4”;
  const char* duckDNS_token = “xxx0bd9-ef52-4846-bd17-xxxxxxxx”;

 

Dưới đây là phần giải thích sơ về đoạn mã Arduino kết hợp các chức năng từ hai đoạn mã trước:

Thư viện

– `#include <WiFi.h>`: Thư viện cho kết nối WiFi.
– `#include <WebServer.h>`: Thư viện cho việc thiết lập máy chủ web.
– `#include <HTTPClient.h>`: Thư viện cho việc thực hiện các yêu cầu HTTP.
– `#include <Wire.h>`: Thư viện cho giao tiếp I2C.
– `#include <RTClib.h>`: Thư viện cho việc điều khiển RTC (Real-Time Clock).

Biến toàn cục

– `const char* ssid = “mixxxxx”;`: Tên SSID cho mạng WiFi.
– `const char* password = “1234567999”;`: Mật khẩu cho mạng WiFi.
– `const char* duckDNS_domain = “subdomain4”;`: Tên miền DuckDNS.
– `const char* duckDNS_token = “xxx0bd9-ef52-4846-bd17-xxxxxxxx”;`: Token DuckDNS.
– `const int ledPin = 15;`: Pin GPIO15 được sử dụng để điều khiển đèn LED.
– `const int MAX_CONNECTION_ATTEMPTS = 3;`: Số lần thử kết nối lại WiFi tối đa.
– `const int WIFI_RETRY_INTERVAL = 7000;`: Thời gian chờ giữa các lần thử kết nối lại WiFi (7 giây).
– `const int DDNS_UPDATE_INTERVAL = 60000;`: Thời gian giữa các lần cập nhật DDNS (1 phút).
– `const unsigned long LIGHT_CYCLE_DURATION = 500;`: Thời gian một chu kỳ sáng tắt là 1 giây.
– `const unsigned long LIGHT_ON_DURATION = 500;`: Thời gian sáng là 0.5 giây.
– `const unsigned long RESTART_INTERVAL = 43200000;`: Thời gian giữa các lần khởi động lại (12 giờ).

Các biến để kiểm soát trạng thái kết nối WiFi và đèn LED:

– `bool isWifiConnected = false;`: Trạng thái kết nối WiFi.
– `bool isAttemptingConnection = false;`: Đang thử kết nối lại WiFi hay không.
– `int wifiConnectionAttempts = 0;`: Số lần thử kết nối lại WiFi.
– `unsigned long lastCycleTime = 0;`: Thời gian của chu kỳ đèn LED.
– `unsigned long lastDDNSUpdateTime = 0;`: Thời gian lần cập nhật DDNS gần nhất.
– `unsigned long lastRestartTime = 0;`: Thời gian lần khởi động lại gần nhất.

WebServer

– `WebServer server(81);`: Tạo một máy chủ web chạy trên cổng 81.
– `const char* htmlPage = R”rawliteral(…)rawliteral”;`: Nội dung HTML của trang web, được định nghĩa dưới dạng raw string literal.

Nội dung HTML

Trang web bao gồm:

– Tiêu đề, form để nhập địa chỉ IP hoặc tên miền và cổng cần kiểm tra, cùng với một số định dạng CSS để trang trí giao diện.
– Một đoạn JavaScript để tự động lấy địa chỉ IP công cộng khi trang web tải xong.

Hàm `setup()`

– `Serial.begin(115200);`: Khởi động giao tiếp serial với tốc độ 115200 baud.
– `pinMode(ledPin, OUTPUT);`: Thiết lập pin GPIO15 làm đầu ra để điều khiển đèn LED.
– `WiFi.begin(ssid, password);`: Bắt đầu kết nối đến mạng WiFi.
– `while (WiFi.status() != WL_CONNECTED)`: Chờ đến khi kết nối thành công tới WiFi.
– `Serial.println(“Connected to WiFi”);`: In ra thông báo kết nối thành công.
– `digitalWrite(ledPin, HIGH);`: Bật đèn LED để báo hiệu trạng thái kết nối WiFi thành công.

Thiết lập máy chủ web:

– `server.on(“/”, HTTP_GET, []() { … });`: Xử lý yêu cầu GET tới trang chủ `/`, gửi nội dung HTML.
– `server.on(“/check”, HTTP_GET, []() { … });`: Xử lý yêu cầu GET tới đường dẫn `/check`, kiểm tra xem các tham số `ip` và `port` có được gửi hay không.

Hàm `loop()`

– `server.handleClient();`: Xử lý các yêu cầu từ client.
– `checkWifiConnection();`: Kiểm tra kết nối WiFi.
– `controlLED();`: Điều khiển đèn LED.
– `if (millis() – lastRestartTime >= RESTART_INTERVAL)`: Kiểm tra thời gian từ lần khởi động lại cuối cùng, nếu vượt quá RESTART_INTERVAL thì khởi động lại ESP32.
– `if (isWifiConnected && millis() – lastDDNSUpdateTime >= DDNS_UPDATE_INTERVAL)`: Nếu đã kết nối WiFi và đến thời gian cập nhật DDNS, thì cập nhật DDNS.

Hàm `checkPort()`

– `bool checkPort(String host, uint16_t port)`: Hàm kiểm tra xem cổng có mở hay không.
– `WiFiClient client;`: Tạo đối tượng WiFiClient để kết nối TCP.
– `bool connected = client.connect(host.c_str(), port);`: Trả về true nếu kết nối tới địa chỉ IP/host và cổng thành công, ngược lại trả về false.
– `client.stop();`: Dừng kết nối.
– `return connected;`: Trả về kết quả kiểm tra cổng.

Hàm `controlLED()`

– Điều khiển đèn LED dựa trên trạng thái kết nối WiFi và thời gian chu kỳ.

Hàm `checkWifiConnection()`

– Kiểm tra trạng thái kết nối WiFi.
– Nếu mất kết nối, thử kết nối lại tối đa MAX_CONNECTION_ATTEMPTS lần.
– Nếu kết nối thành công, cập nhật trạng thái và thực hiện cập nhật DDNS.

Hàm `updateDDNS()`

– Lấy địa chỉ IP công cộng và cập nhật tên miền DuckDNS với địa chỉ IP này.

Hàm `restartESP32()`

– `Serial.println(“Restarting ESP32…”);`: In ra thông báo khởi động lại.
– `ESP.restart();`: Khởi động lại ESP32.

Tổng kết

Đoạn mã này kết hợp các chức năng của hai đoạn mã trước, cung cấp một máy chủ web trên ESP32 để kiểm tra các cổng mở của một địa chỉ IP hoặc tên miền, và đồng thời quản lý kết nối WiFi và cập nhật DDNS. Nó cũng có chức năng điều khiển đèn LED để báo hiệu trạng thái kết nối và khởi động lại ESP32 định kỳ.

 

Sử Dụng ESP32 Làm Trang Web Kiểm Tra Cổng Đóng/Mở

2Screenshot 2024 06 16 143007

Sử Dụng ESP32 Làm Trang Web Kiểm Tra Cổng Đóng/Mở

ESP32 với khả năng linh hoạt và mạnh mẽ, không chỉ là một nền tảng IoT tiên tiến mà còn là một công cụ lý tưởng để xây dựng các ứng dụng như trang web kiểm tra cổng mạng. Trang web này giúp người dùng kiểm tra trạng thái mở hoặc đóng của các cổng mạng trên hệ thống của mình một cách dễ dàng và hiệu quả.

2Screenshot 2024 06 16 143007

Tính Năng Trang Web

 1.  Kiểm Tra Cổng Mạng: ESP32 được lập trình để quét và báo cáo trạng thái của các cổng mạng, từ đó người dùng có thể biết được cổng đóng (closed) hoặc mở (open).

 2.  Giao Diện Người Dùng Thân Thiện: Giao diện đơn giản và thân thiện với người dùng, cho phép họ dễ dàng nhập số cổng cần kiểm tra và nhận kết quả ngay lập tức.

 3.  Tích Hợp Linh Hoạt: Khả năng hoạt động trên nhiều nền tảng khác nhau, bao gồm cả máy tính và thiết bị di động, giúp người dùng tiếp cận và sử dụng trang web một cách tiện lợi.

Ngoài ra chỉ cần mở cổng ra bên ngoài và có được ip public ta có thể truy cập từ xa vào để kiểm tra tình trạng đóng mở cổng của các ip. Hoặc có thể nhúng vào web nếu bạn đang sài hosting.

Trong code dưới đây bởi vì tài nguyên phần cứng trên ESP32 có hạn nên tôi chỉ kiểm tra trạng thái mỗi cổng 1 lần. Cùng với việc chúng ta sẽ cố định ip của ESP32 trên router nếu cần mở port và không muốn kiểm tra ip của esp32 mỗi lần kết nối để cho code được ngắn gọn và đơn giản nhất.

#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>

const char* ssid = "mĩxxxx";
const char* password = "1234567999";
const int ledPin = 15; 

WebServer server(81);
const char* htmlPage = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
  <title>ESP32 Port Checker</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    body {
      font-family: Arial, sans-serif;
      text-align: center;
      background-color: #f0f0f0;
      margin: 0;
      padding: 0;
    }
    h2 {
      color: #333;
    }
    form {
      background: #fff;
      padding: 20px;
      border-radius: 5px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
      display: inline-block;
      margin-top: 50px;
    }
    label {
      display: block;
      margin-bottom: 8px;
      color: #555;
    }
    input[type="text"] {
      width: calc(100% - 22px);
      padding: 10px;
      margin-bottom: 20px;
      border: 1px solid #ddd;
      border-radius: 3px;
    }
    input[type="submit"] {
      padding: 10px 20px;
      border: none;
      background-color: #007bff;
      color: white;
      border-radius: 3px;
      cursor: pointer;
    }
    input[type="submit"]:hover {
      background-color: #0056b3;
    }
  </style>
  <script>
    async function fetchPublicIP() {
      const response = await fetch('https://api.ipify.org?format=json');
      const data = await response.json();
      document.getElementById('ip').value = data.ip;
    }
    window.onload = fetchPublicIP;
  </script>
</head>
<body>
  <h2>ESP32 Port Checker</h2>
  <form action="/check" method="get">
    <label for="ip">IP/Domain:</label>
    <input type="text" id="ip" name="ip"><br>
    <label for="port">Port:</label>
    <input type="text" id="port" name="port"><br>
    <input type="submit" value="Check">
  </form>
  %s
</body>
</html>
)rawliteral";

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  server.on("/", HTTP_GET, []() {
    server.send(200, "text/html", htmlPage);
  });

  // Check
  server.on("/check", HTTP_GET, []() {
    if (server.hasArg("ip") && server.hasArg("port")) {
      String ip = server.arg("ip");
      String port = server.arg("port");
      bool isOpen = checkPort(ip, port.toInt());

      String result = "<p>Checking " + ip + ":" + port + " - ";
      result += isOpen ? "Open" : "Closed";
      result += "</p>";
      server.send(200, "text/html", String(htmlPage) + result);
    } else {
      server.send(200, "text/html", String(htmlPage) + "<p>Invalid input</p>");
    }
  });

  server.begin();
}

void loop() {
  server.handleClient();
}

bool checkPort(String host, uint16_t port) {
  WiFiClient client;
  return client.connect(host.c_str(), port);
}

 

hãy thay đổi thông tin sau nếu cần.

const char* ssid = "xxxx"; //tên wifi của bạn
const char* password = "passwd"; //mật khẩu wifi

WebServer server(81); // đang port 81 đổi thành port khác nếu cần

Sau khi nạp code và esp32 đã kết nối tới wifi hãy kiểm tra địa chỉ ip của ESP32 và truy cập vào theo địa chỉ http://IP:81 để kiểm tra cổng  nếu mở port ra ngoài thay IP bằng IPPublic là được.

ESP32 không chỉ là một nền tảng IoT mạnh mẽ mà còn là sự lựa chọn hoàn hảo cho việc xây dựng các ứng dụng nhu cầu cá nhân, mang lại sự đơn giản, hiệu quả và và chi phí rẻ. Hãy vọc ESP32 để có những ứng dụng hay!

 

Dưới đây là phần giải thích sơ về đoạn mã Arduino trên:

Thư viện

– `#include <WiFi.h>`: Thư viện cho kết nối WiFi.
– `#include <WebServer.h>`: Thư viện cho việc thiết lập máy chủ web.
– `#include <HTTPClient.h>`: Thư viện cho việc thực hiện các yêu cầu HTTP.

Biến toàn cục

– `const char* ssid = “mĩxxxx”;`: Tên SSID cho mạng WiFi.
– `const char* password = “1234567999”;`: Mật khẩu cho mạng WiFi.
– `const int ledPin = 15;`: Pin GPIO15 được sử dụng để điều khiển đèn LED.

– `WebServer server(81);`: Tạo một máy chủ web chạy trên cổng 81.
– `const char* htmlPage = R”rawliteral(…)rawliteral”;`: Nội dung HTML của trang web, được định nghĩa dưới dạng raw string literal.

Nội dung HTML

– HTML trang web bao gồm một tiêu đề, một form để nhập địa chỉ IP hoặc tên miền và cổng cần kiểm tra, cùng với một số định dạng CSS để trang trí giao diện.
– Một đoạn JavaScript để tự động lấy địa chỉ IP công cộng khi trang web tải xong.

Hàm `setup()`

– `Serial.begin(115200);`: Khởi động giao tiếp serial với tốc độ 115200 baud.
– `WiFi.begin(ssid, password);`: Bắt đầu kết nối đến mạng WiFi.
– `while (WiFi.status() != WL_CONNECTED)`: Chờ đến khi kết nối thành công tới WiFi.
– `Serial.println(“Connected to WiFi”);`: In ra thông báo kết nối thành công.
– `pinMode(ledPin, OUTPUT);`: Thiết lập pin GPIO15 làm đầu ra để điều khiển đèn LED.
– `digitalWrite(ledPin, HIGH);`: Bật đèn LED để báo hiệu kết nối WiFi thành công.

Thiết lập máy chủ web

– `server.on(“/”, HTTP_GET, []() { … });`: Xử lý yêu cầu GET tới trang chủ `/`, gửi nội dung HTML.
– `server.on(“/check”, HTTP_GET, []() { … });`: Xử lý yêu cầu GET tới đường dẫn `/check`, kiểm tra xem các tham số `ip` và `port` có được gửi hay không.

Hàm `loop()`

– `server.handleClient();`: Xử lý các yêu cầu từ client.

Hàm `checkPort()`

– `bool checkPort(String host, uint16_t port)`: Hàm kiểm tra xem cổng có mở hay không.
– `WiFiClient client;`: Tạo đối tượng WiFiClient để kết nối TCP.
– `return client.connect(host.c_str(), port);`: Trả về true nếu kết nối tới địa chỉ IP/host và cổng thành công, ngược lại trả về false.

Tổng kết

Đoạn mã trên kết nối ESP32 tới mạng WiFi, thiết lập một máy chủ web để người dùng có thể nhập vào địa chỉ IP hoặc tên miền và cổng để kiểm tra xem cổng có mở hay không. Khi người dùng gửi yêu cầu kiểm tra, ESP32 sẽ thực hiện kết nối tới địa chỉ IP và cổng đó, sau đó trả về kết quả cho người dùng biết cổng đó có mở hay không. Đèn LED được bật sáng để báo hiệu trạng thái kết nối WiFi thành công.

Biến ESP32 Thành Điểm Truy Cập Wi-Fi và Cập Nhật Firmware qua Giao Diện Web

Screenshot 2024 06 16 123729

Biến ESP32 Thành Điểm Truy Cập Wi-Fi và Cập Nhật Firmware qua Giao Diện Web

112233446666

Trong bài viết này, chúng ta sẽ nạp code biến chiếc ESP32 của bạn thành một điểm truy cập Wi-Fi, đồng thời cung cấp một giao diện web đơn giản để cập nhật firmware. Giải pháp này mang lại sự tiện lợi tối đa cho việc quản lý và nâng cấp phần mềm của thiết bị, đặc biệt là trong các trường hợp triển khai ở những vị trí khó tiếp cận.

 

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
 
const char* host = "esp32";
const char* ssid = "mixxxxx";
const char* password = ""; //  passwd
 
const int ledPin = 15; // Use pin GPIO15 to control LED
 
WebServer server(80);
 
/* Style */
String style =
"<style>"
"#file-input,input{width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px}"
"input{background:#f1f1f1;border:0;padding:0 15px}body{background:#2ecc71;font-family:sans-serif;font-size:14px;color:#777}"
"#file-input{padding:0;border:1px solid #ddd;line-height:44px;text-align:left;display:block;cursor:pointer}"
"#bar,#prgbar{background-color:#f1f1f1;border-radius:10px}#bar{background-color:#3498db;width:0%;height:10px}"
"form{background:#fff;max-width:258px;margin:75px auto;padding:30px;border-radius:5px;text-align:center}"
".btn{background:#3498db;color:#fff;cursor:pointer}</style>";
 
/* Server Index Page */
String serverIndex = 
"<script>"
"function sub(obj){"
"var fileName = obj.value.split('\\\\');"
"document.getElementById('file-input').innerHTML = '   '+ fileName[fileName.length-1];"
"};"
"document.addEventListener('DOMContentLoaded', function() {"
"document.getElementById('upload_form').addEventListener('submit', function(e) {"
"e.preventDefault();"
"var form = document.getElementById('upload_form');"
"var data = new FormData(form);"
"var xhr = new XMLHttpRequest();"
"xhr.open('POST', '/update-firmware', true);"
"xhr.upload.addEventListener('progress', function(evt) {"
"if (evt.lengthComputable) {"
"var percentComplete = Math.round((evt.loaded / evt.total) * 100);"
"document.getElementById('prg').innerHTML = 'progress: ' + percentComplete + '%';"
"document.getElementById('bar').style.width = percentComplete + '%';"
"}"
"}, false);"
"xhr.onload = function() {"
"if (xhr.status === 200) {"
"console.log('success!');"
"alert('update-firmware OK');"
"} else {"
"console.log('error!');"
"}"
"};"
"xhr.send(data);"
"});"
"});"
"</script>"
"<form method='POST' action='/update-firmware' enctype='multipart/form-data' id='upload_form'>"
"<input type='file' name='update' id='file' onchange='sub(this)' style=display:none>"
"<label id='file-input' for='file'>   Choose file...</label>"
"<input type='submit' class=btn value='Update'>"
"<br><br>"
"<div id='prg'></div>"
"<br><div id='prgbar'><div id='bar'></div></div><br></form>" + style;
 
/* setup function */
void setup(void) {
  Serial.begin(115200);
 
  // Set up ESP32 as Access Point
  WiFi.softAP(ssid, password);
 
  IPAddress IP(10, 10, 10, 1); // Set AP's IP address
  IPAddress subnet(255, 255, 255, 0); // Set subnet
  WiFi.softAPConfig(IP, IP, subnet);
 
  // Print IP infor
  Serial.println("");
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
 
  // Turn on LED when WiFi connection is successful
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
 
  /*use mdns for host name resolution*/
  if (!MDNS.begin(host)) { //http://esp32
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
 
  /*handling uploading firmware file */
  server.on("/update-firmware", HTTP_POST, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
    if (!Update.hasError()) {
      Serial.println("update-firmware OK");
      ESP.restart(); // Khởi động lại ESP32 sau khi cập nhật thành công
    }
  }, []() {
    HTTPUpload& upload = server.upload();
    if (upload.status == UPLOAD_FILE_START) {
      Serial.printf("Update: %s\n", upload.filename.c_str());
      if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_WRITE) {
      /* flashing firmware to ESP*/
      if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
        Update.printError(Serial);
      }
    } else if (upload.status == UPLOAD_FILE_END) {
      if (Update.end(true)) { //true to set the size to the current progress
        Serial.printf("Update Success: %u\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
    }
  });
  
  // Serve the upload page directly
  server.on("/", HTTP_GET, []() {
    server.sendHeader("Connection", "close");
    server.send(200, "text/html", serverIndex); // Directly serve the upload page
  });
  
  server.begin();
}
 
void loop(void) {
  server.handleClient();
  delay(1);
}

Sau kết nối với wifi phát ra trên esp32 này để truy cập vào trang update firmware hãy gõ địa chỉ http://esp32/ hoặc http://10.10.10.1 . Nếu cần hãy thay đổi thông tin sau theo ý muốn.

const char* host = "esp32"; //  local host
const char* ssid = "mixxxxx"; // tên wifi 
const char* password = "passwd"; //  mật khẩu

IPAddress IP(10, 10, 10, 1); // Thiết lập địa chỉ IP của AP
IPAddress subnet(255, 255, 255, 0); // Thiết lập mặt nạ mạng

Screenshot 2024 06 16 123729

Chức năng chính của code

Khi ESP32 được khởi động, nó sẽ thiết lập một mạng Wi-Fi với tên (SSID) và mật khẩu đã được chỉ định. Sau khi kết nối thành công, bạn có thể truy cập vào mạng Wi-Fi này và sử dụng địa chỉ IP 10.10.10.1 để mở giao diện web trên trình duyệt của mình.

Giao diện web trực quan

Giao diện web được thiết kế với một trang đơn giản và thân thiện với người dùng, bao gồm các thành phần cơ bản như nút chọn tệp và nút tải lên.

Người dùng chỉ cần chọn tệp firmware cần cập nhật và nhấn “Update”. Trang web cũng hiển thị một thanh tiến trình, giúp người dùng dễ dàng theo dõi quá trình tải lên.

 

Quá trình cập nhật firmware

  1. Bắt đầu tải lên: ESP32 nhận diện tệp firmware mới và chuẩn bị cho quá trình cập nhật.
  2. Ghi dữ liệu: Tệp firmware được chia thành nhiều phần nhỏ và từng phần được ghi vào bộ nhớ của ESP32.
  3. Kết thúc cập nhật: Sau khi toàn bộ tệp firmware được ghi thành công, ESP32 xác nhận quá trình hoàn tất và tự khởi động lại để áp dụng phiên bản firmware mới.

Sự tiện lợi và an toàn

Đèn LED trên ESP32 sẽ sáng lên khi thiết bị đã sẵn sàng để kết nối Wi-Fi, giúp người dùng dễ dàng nhận biết trạng thái của thiết bị. Hệ thống mDNS cũng được sử dụng, cho phép người dùng truy cập ESP32 bằng tên miền “esp32.local” thay vì phải nhớ địa chỉ IP.

LƯU Ý rằng nếu file firmware.bin mà bạn upload lên không có chức năng upload firmware thì sẽ không còn tính năng này nữa.

 

Dưới đây là phần giải thích về đoạn mã Arduino trên:

Thư viện

– `#include <Arduino.h>`: Thư viện cơ bản cho lập trình Arduino.
– `#include <WiFi.h>`: Thư viện cho kết nối WiFi.
– `#include <WiFiClient.h>`: Thư viện cho việc tạo kết nối WiFi client.
– `#include <WebServer.h>`: Thư viện cho việc tạo một Web Server trên ESP32.
– `#include <ESPmDNS.h>`: Thư viện cho Multicast DNS (mDNS) để cho phép truy cập thiết bị thông qua tên miền thay vì địa chỉ IP.
– `#include <Update.h>`: Thư viện cho việc cập nhật firmware qua mạng (OTA).

Biến toàn cục

– `const char* host = “esp32”;`: Tên máy chủ để truy cập thông qua mDNS.
– `const char* ssid = “mixxxxx”;`: Tên SSID cho mạng WiFi.
– `const char* password = “”;`: Mật khẩu cho mạng WiFi.
– `const int ledPin = 15;`: Pin GPIO15 được sử dụng để điều khiển đèn LED.
– `WebServer server(80);`: Tạo một Web Server chạy trên cổng 80.

Biến chuỗi cho giao diện web

– `String style`: Chuỗi chứa mã CSS cho giao diện web.
– `String serverIndex`: Chuỗi chứa mã HTML và JavaScript cho trang upload firmware.

Hàm `setup()`

– `Serial.begin(115200);`: Khởi động giao tiếp serial với tốc độ 115200 baud.
– `WiFi.softAP(ssid, password);`: Thiết lập ESP32 như một Access Point (AP) với SSID và mật khẩu.
– `WiFi.softAPConfig(IP, IP, subnet);`: Thiết lập địa chỉ IP và subnet cho AP.
– `Serial.println(WiFi.softAPIP());`: In địa chỉ IP của AP lên Serial Monitor.
– `pinMode(ledPin, OUTPUT);`: Thiết lập pin GPIO15 làm đầu ra.
– `digitalWrite(ledPin, HIGH);`: Bật đèn LED.
– `MDNS.begin(host);`: Thiết lập mDNS để truy cập thiết bị thông qua tên miền `http://esp32`.

Cài đặt Server

– `server.on(“/update-firmware”, HTTP_POST, …);`: Định nghĩa hàm xử lý cho việc upload firmware.
– Khi nhận POST request tại `/update-firmware`, nó sẽ xử lý file tải lên và cập nhật firmware.
– `server.on(“/”, HTTP_GET, …);`: Định nghĩa hàm xử lý cho việc tải trang web upload firmware.

Hàm `loop()`

– `server.handleClient();`: Xử lý các yêu cầu từ client đến Web Server.
– `delay(1);`: Tạm dừng một khoảng thời gian ngắn (1ms).

Chi tiết các xử lý upload firmware

– `HTTPUpload& upload = server.upload();`: Nhận dữ liệu tải lên.
– `Update.begin(UPDATE_SIZE_UNKNOWN)`: Bắt đầu quá trình cập nhật firmware.
– `Update.write(upload.buf, upload.currentSize)`: Ghi dữ liệu firmware lên bộ nhớ.
– `Update.end(true)`: Kết thúc quá trình cập nhật và thiết lập kích thước hiện tại.
– `ESP.restart()`: Khởi động lại ESP32 sau khi cập nhật thành công.

Tổng kết

Mã nguồn này mang lại một giải pháp hiệu quả cho việc quản lý và cập nhật firmware của thiết bị ESP32 thông qua mạng không dây. Với giao diện web đơn giản và dễ sử dụng, việc duy trì và nâng cấp firmware trở nên dễ dàng hơn bao giờ hết.

Duck DDNS cho ESP32

duck0

Duck DDNS trên ESP32 subdomain giá rẻ cho mọi người.

Duckdns cho tạo 5 sub miễn phí đăng ký đơn giản bằng tài khoản google, github… lợi dụng điều này ta sẽ lấy subdomain miễn phí( mất phí phần cứng tối thiểu) để cập nhật publicIP ở nhà thay cho các dịch vụ ddns có tính phí khác bằng cách nạp code cho board esp32.

Với subdomain này khỏi mua ip tĩnh, dyndns, noip,… có thể dùng để kéo onvif cho imou, ezviz,… miễn phí tới khi duckdns đóng dịch vụ này thì ta chuyển qua thằng khác.

1.Chuẩn bị: ESP32 giá 50cành bấm vào xem board dùng nếu nạp đúng code này.

2.Cài Arduino IDE và cài 1 số thư viện nếu quá trình chạy code báo lỗi, nếu chưa biết cài thì cứ google.

Trước khi nạp code cần tạo acc Duckdns ,reg tên miền tránh trường hợp reg tên miền không được vì bị trùng với người khác.

 

Code: copee code phía dưới. cho vào Arduino IDE.

#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <RTClib.h>

const char* ssid = "mixxxxx";
const char* password = "1234567999";
const char* duckDNS_domain = "subdomain4";
const char* duckDNS_token = "xxx0bd9-ef52-4846-bd17-xxxxxxxx";
RTC_DS3231 rtc;

const int ledPin = 15; // Sử dụng chân GPIO15 để điều khiển LED
const int MAX_CONNECTION_ATTEMPTS = 3; // Số lần thử kết nối lại WiFi tối đa
const int WIFI_RETRY_INTERVAL = 7000; // Thời gian chờ giữa các lần thử kết nối lại WiFi (7 giây)
const int DDNS_UPDATE_INTERVAL = 60000; // Thời gian giữa các lần cập nhật DDNS (1 phút)
const unsigned long LIGHT_CYCLE_DURATION = 500; // Thời gian một chu kỳ sáng tắt là 1 giây
const unsigned long LIGHT_ON_DURATION = 500; // Thời gian sáng là 0.5 giây
const unsigned long RESTART_INTERVAL = 43200000; // Thời gian giữa các lần khởi động lại (12 giờ)

bool isWifiConnected = false;
bool isAttemptingConnection = false;
int wifiConnectionAttempts = 0;
unsigned long lastCycleTime = 0;
unsigned long lastDDNSUpdateTime = 0;
unsigned long lastRestartTime = 0;
void updateDDNS();
void checkWifiConnection();
void controlLED();
void restartESP32();

void setup() {
 Serial.begin(115200);

 pinMode(ledPin, OUTPUT); // Đặt chân GPIO để điều khiển đèn là đầu ra

 // Khởi động kết nối
 Wire.begin();

 // Khởi động kết nối tới mạng WiFi
 WiFi.begin(ssid, password);
 Serial.print("Connecting to WiFi");
 checkWifiConnection();
 updateDDNS();
 lastRestartTime = millis(); // Gán thời gian khởi đầu cho biến lastRestartTime
}
void loop() {
 // Chạy hàm kiểm tra kết nối WiFi mỗi lần
 checkWifiConnection();
 // Kiểm tra và điều khiển trạng thái LED
 controlLED();
 // Kiểm tra và khởi động lại ESP32 hàng ngày
 if (millis() - lastRestartTime >= RESTART_INTERVAL) {
 restartESP32();
 }
// Cập nhật DDNS mỗi phút nếu đã kết nối và đã đến thời gian cập nhật
 if (isWifiConnected && millis() - lastDDNSUpdateTime >= DDNS_UPDATE_INTERVAL) {
 updateDDNS();
 lastDDNSUpdateTime = millis();
 }
}
void controlLED() {
 unsigned long currentMillis = millis();

 // Kiểm tra nếu đã đến thời gian cho một chu kỳ mới
 if (isWifiConnected && (currentMillis - lastCycleTime >= LIGHT_CYCLE_DURATION)) {
 lastCycleTime = currentMillis;
 // Nếu có kết nối WiFi, sáng LED và bỏ qua điều kiện chớp tắt ban đầu
 digitalWrite(ledPin, HIGH);
 return;
 }
 // Kiểm tra nếu LED cần được tắt
 if (currentMillis - lastCycleTime >= LIGHT_ON_DURATION) {
 digitalWrite(ledPin, LOW);
 } else {
 digitalWrite(ledPin, HIGH); // Bắt đầu với trạng thái sáng LED
 }
}
void checkWifiConnection() {
 if (WiFi.status() != WL_CONNECTED) {
 // Nếu mất kết nối WiFi
 isWifiConnected = false;
 // Nếu không phải là lần thử kết nối lại
 if (!isAttemptingConnection) {
 // Bắt đầu quá trình thử kết nối lại
 isAttemptingConnection = true;
 wifiConnectionAttempts = 0;
 }
 // Kết nối lại WiFi nếu cần thiết và chưa vượt quá số lần thử tối đa
 if (isAttemptingConnection && wifiConnectionAttempts < MAX_CONNECTION_ATTEMPTS) {
 if (millis() - lastCycleTime >= WIFI_RETRY_INTERVAL) {
 wifiConnectionAttempts++;
 Serial.print("Attempting to reconnect to WiFi (Attempt ");
 Serial.print(wifiConnectionAttempts);
 Serial.println(")");
 WiFi.begin(ssid, password);
 lastCycleTime = millis();
 }
 } else {
 isAttemptingConnection = false;
 Serial.println("WiFi connection failed after multiple attempts.");
 digitalWrite(ledPin, LOW); // Nhấp nháy LED khi kết nối WiFi thất bại
 }
 } else {
 isWifiConnected = true;
 isAttemptingConnection = false;
 wifiConnectionAttempts = 0; 
 updateDDNS();
 }
}
void updateDDNS() {
 String duckDNS_update_url = "http://www.duckdns.org/update?domains=" + String(duckDNS_domain) + "&token=" + String(duckDNS_token) + "&ip=";
 HTTPClient http;
 http.begin("https://ipv4.icanhazip.com");
 int httpCode = http.GET();
 String currentIP = "";
 if (httpCode == HTTP_CODE_OK) {
 currentIP = http.getString();
 Serial.println("Current IP: " + currentIP);
 HTTPClient httpUpdate;
 httpUpdate.begin(duckDNS_update_url + currentIP);
 int httpUpdateCode = httpUpdate.GET();
 if (httpUpdateCode == HTTP_CODE_OK) {
 Serial.println("DDNS update success");
 }
 httpUpdate.end();
 } else {
 Serial.println("Failed to connect to IP service");
 }
 http.end();
}
void restartESP32() {
 Serial.println("Restarting ESP32...");
 ESP.restart();
}

 

sửa thông tin sau theo ý bạn:

const char* ssid = “tên wifi”;
const char* password = “mật khẩu wifi”;
const char* duckDNS_domain = “subdomain4”;
const char* duckDNS_token = “xxx0bd9-ef52-4846-bd17-xxxxxxxx”;

Cắm board vào và nạp tạo 1 tên wifi 2.4g với thông tin đã đặt và tận hưởng.Trong code mình sử dụng chân LED trên board làm báo hiệu trạng thái hoạt động và đã chú thích khá nhiều nên chắc dễ hiểu nhỉ.

duck0

Vì là fix cứng wifi, passwd, subdomain, token. nên khá bất tiện yêu cầu phải có  máy tính hoặc sài điện thoại cài Arduino Studio – Arduino IDE cái nạp tên điện thoại mình chưa thử. và do  giá rẻ nên phải bỏ công làm.

Mình đang viết lại để có thể thay đổi thông như hình dưới có nạp từ xa khi mở port, có thêm ddns của swanndvr.net thằng này cũng tạo được 6 subdomain miễn phí. dù cách nào đi nữa ban đầu vẫn phải nạp code cho esp32 rồi mới nạp từ xa được.

 

duck

Dưới đây là phần giải thích sơ về đoạn mã Arduino trên:

Thư viện

– `#include <WiFi.h>`: Thư viện cho kết nối WiFi.
– `#include <HTTPClient.h>`: Thư viện cho việc thực hiện các yêu cầu HTTP.
– `#include <Wire.h>`: Thư viện cho giao tiếp I2C.
– `#include <RTClib.h>`: Thư viện cho việc sử dụng Real-Time Clock (RTC).

Biến toàn cục

– `const char* ssid = “mixxxxx”;`: Tên SSID cho mạng WiFi.
– `const char* password = “1234567999”;`: Mật khẩu cho mạng WiFi.
– `const char* duckDNS_domain = “subdomain4”;`: Tên miền DuckDNS.
– `const char* duckDNS_token = “xxx0bd9-ef52-4846-bd17-xxxxxxxx”;`: Token DuckDNS để cập nhật địa chỉ IP.
– `RTC_DS3231 rtc;`: Đối tượng RTC sử dụng DS3231.

Các biến cấu hình và trạng thái

– `const int ledPin = 15;`: Pin GPIO15 được sử dụng để điều khiển đèn LED.
– `const int MAX_CONNECTION_ATTEMPTS = 3;`: Số lần thử kết nối lại WiFi tối đa.
– `const int WIFI_RETRY_INTERVAL = 7000;`: Thời gian chờ giữa các lần thử kết nối lại WiFi (7 giây).
– `const int DDNS_UPDATE_INTERVAL = 60000;`: Thời gian giữa các lần cập nhật DDNS (1 phút).
– `const unsigned long LIGHT_CYCLE_DURATION = 500;`: Thời gian một chu kỳ sáng tắt là 1 giây.
– `const unsigned long LIGHT_ON_DURATION = 500;`: Thời gian sáng là 0.5 giây.
– `const unsigned long RESTART_INTERVAL = 43200000;`: Thời gian giữa các lần khởi động lại (12 giờ).

– `bool isWifiConnected = false;`: Biến trạng thái kết nối WiFi.
– `bool isAttemptingConnection = false;`: Biến trạng thái thử kết nối lại WiFi.
– `int wifiConnectionAttempts = 0;`: Số lần thử kết nối lại WiFi.
– `unsigned long lastCycleTime = 0;`: Thời gian của chu kỳ đèn LED cuối cùng.
– `unsigned long lastDDNSUpdateTime = 0;`: Thời gian cập nhật DDNS lần cuối.
– `unsigned long lastRestartTime = 0;`: Thời gian khởi động lại lần cuối.

Hàm `setup()`

– `Serial.begin(115200);`: Khởi động giao tiếp serial với tốc độ 115200 baud.
– `pinMode(ledPin, OUTPUT);`: Thiết lập pin GPIO15 làm đầu ra để điều khiển đèn LED.
– `Wire.begin();`: Khởi động giao tiếp I2C.
– `WiFi.begin(ssid, password);`: Bắt đầu kết nối đến mạng WiFi.
– `checkWifiConnection();`: Kiểm tra và kết nối lại WiFi nếu cần.
– `updateDDNS();`: Cập nhật địa chỉ IP lên DuckDNS.
– `lastRestartTime = millis();`: Gán thời gian khởi đầu cho biến `lastRestartTime`.

Hàm `loop()`

– `checkWifiConnection();`: Kiểm tra trạng thái kết nối WiFi và kết nối lại nếu cần.
– `controlLED();`: Điều khiển trạng thái đèn LED.
– `if (millis() – lastRestartTime >= RESTART_INTERVAL)`: Kiểm tra và khởi động lại ESP32 sau khoảng thời gian đã định.
– `if (isWifiConnected && millis() – lastDDNSUpdateTime >= DDNS_UPDATE_INTERVAL)`: Cập nhật địa chỉ IP lên DuckDNS nếu đã kết nối WiFi và đã đến thời gian cập nhật.

Hàm `controlLED()`

– `unsigned long currentMillis = millis();`: Lấy thời gian hiện tại.
– `if (isWifiConnected && (currentMillis – lastCycleTime >= LIGHT_CYCLE_DURATION))`: Kiểm tra và điều khiển đèn LED nếu đã kết nối WiFi.
– `if (currentMillis – lastCycleTime >= LIGHT_ON_DURATION)`: Tắt đèn LED nếu đã đến thời gian tắt.

Hàm `checkWifiConnection()`

– `if (WiFi.status() != WL_CONNECTED)`: Kiểm tra trạng thái kết nối WiFi.
– `if (!isAttemptingConnection)`: Bắt đầu thử kết nối lại nếu chưa thực hiện.
– `if (isAttemptingConnection && wifiConnectionAttempts < MAX_CONNECTION_ATTEMPTS)`: Thử kết nối lại WiFi nếu chưa vượt quá số lần thử tối đa.
– `WiFi.begin(ssid, password);`: Kết nối lại WiFi.
– `if (WiFi.status() == WL_CONNECTED)`: Cập nhật địa chỉ IP lên DuckDNS nếu kết nối WiFi thành công.

Hàm `updateDDNS()`

– `HTTPClient http;`: Tạo đối tượng HTTPClient để gửi yêu cầu HTTP.
– `http.begin(“https://ipv4.icanhazip.com”);`: Gửi yêu cầu GET để lấy địa chỉ IP hiện tại.
– `int httpCode = http.GET();`: Lấy mã trạng thái HTTP.
– `if (httpCode == HTTP_CODE_OK)`: Nếu yêu cầu thành công, lấy địa chỉ IP hiện tại và cập nhật lên DuckDNS.

Hàm `restartESP32()`

– `Serial.println(“Restarting ESP32…”);`: In thông báo khởi động lại ESP32.
– `ESP.restart();`: Khởi động lại ESP32.

Tổng kết

Đoạn mã trên kết nối ESP32 tới mạng WiFi, cập nhật địa chỉ IP lên DuckDNS, điều khiển đèn LED báo hiệu trạng thái kết nối WiFi, và khởi động lại ESP32 sau khoảng thời gian đã định. Chương trình cũng xử lý việc kiểm tra và kết nối lại WiFi nếu mất kết nối và thực hiện cập nhật DDNS định kỳ.

 

KIỂM TRA PORT

IPv6 của bạn: Đang lấy...