ESP32 Captive Portal Search Engine Code
#include <DNSServer.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
// ---------------- USER CONFIGURATION ----------------
// Backend Router (Internet connection for ESP32)
const char* sta_ssid = "Airtel_X"; // Aapka router ka naam
const char* sta_pass = "Gau@0369"; // Aapka router ka password
// ESP32 Access Point (Network name for users)
const char* ap_ssid = "ESP32 SEARCH ENGINE"; // AP Name jo mobile mein show hoga
// ----------------------------------------------------
const byte DNS_PORT = 53;
DNSServer dnsServer;
WebServer server(80);
// Function to safely encode search queries for URL (e.g. "Elon Musk" -> "Elon%20Musk")
String urlEncode(String str) {
String encodedString = "";
char c;
char code0;
char code1;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c == ' ') {
encodedString += "%20";
} else if (isalnum(c)) {
encodedString += c;
} else {
code1 = (c & 0xf) + '0';
if ((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A';
c = (c >> 4) & 0xf;
code0 = c + '0';
if (c > 9) code0 = c - 10 + 'A';
encodedString += '%';
encodedString += code0;
encodedString += code1;
}
}
return encodedString;
}
// 🌐 HTML: The Home Page (Search Engine UI)
void handleRoot() {
String html = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width, initial-scale=1'>";
html += "<title>ESR369 Search</title>";
html += "<style>";
html += "body { font-family: Arial, sans-serif; text-align: center; margin-top: 20%; background-color: #f2f2f2; }";
html += "h1 { font-size: 50px; color: #4285F4; margin-bottom: 10px; }";
html += "input[type=text] { width: 80%; max-width: 400px; padding: 12px; border: 1px solid #dfe1e5; border-radius: 24px; outline: none; font-size: 16px; }";
html += "input[type=submit] { margin-top: 20px; padding: 10px 20px; background-color: #f8f9fa; border: 1px solid #f8f9fa; border-radius: 4px; cursor: pointer; color: #3c4043; }";
html += "</style></head><body>";
html += "<h1>ESR369</h1>";
html += "<form action='/search' method='GET'>";
html += "<input type='text' name='q' placeholder='Search the web...' required><br>";
html += "<input type='submit' value='ESR369 Search'>";
html += "</form>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// 🌐 HTML & Backend Logic: The Search Results Page
void handleSearch() {
if (!server.hasArg("q")) {
server.sendHeader("Location", "/");
server.send(302, "text/plain", "");
return;
}
String query = server.arg("q");
String resultTitle = "No exact match found.";
String resultText = "Sorry, we couldn't find a summary for your search via our backend API. Please try a different keyword (e.g., 'India', 'Internet', 'Computer').";
// Check if ESP32 is connected to the Internet (AIRTEL)
if (WiFi.status() == WL_CONNECTED) {
WiFiClientSecure *client = new WiFiClientSecure;
client->setInsecure(); // Bypass SSL certificate check for simplicity
HTTPClient https;
// Wikipedia API call for a clean summary
String apiUrl = "https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exsentences=3&exlimit=1&titles=" + urlEncode(query) + "&explaintext=1&formatversion=2&format=json";
Serial.println("Fetching: " + apiUrl);
if (https.begin(*client, apiUrl)) {
int httpCode = https.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = https.getString();
// Parse the JSON data
DynamicJsonDocument doc(4096);
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
String extract = doc["query"]["pages"][0]["extract"].as<String>();
if (extract != "null" && extract.length() > 0) {
resultTitle = doc["query"]["pages"][0]["title"].as<String>();
resultText = extract;
}
}
}
https.end();
}
delete client;
} else {
resultText = "Backend Error: ESP32 is not connected to AIRTEL WiFi. Cannot fetch internet results.";
}
// Generate Results HTML Page
String html = "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width, initial-scale=1'>";
html += "<title>ESR369 - Results</title>";
html += "<style>";
html += "body { font-family: Arial, sans-serif; padding: 20px; background-color: #fff; }";
html += ".header { display: flex; align-items: center; border-bottom: 1px solid #ebebeb; padding-bottom: 15px; margin-bottom: 20px; }";
html += ".header h2 { color: #4285F4; margin: 0; margin-right: 20px; cursor: pointer; }";
html += "input[type=text] { padding: 10px; width: 60%; max-width: 300px; border: 1px solid #dfe1e5; border-radius: 20px; outline: none; }";
html += ".result-box { max-width: 600px; }";
html += ".title { color: #1a0dab; font-size: 20px; text-decoration: none; font-weight: normal; margin-bottom: 5px; }";
html += ".url { color: #202124; font-size: 14px; margin-bottom: 5px; }";
html += ".desc { color: #4d5156; font-size: 14px; line-height: 1.58; }";
html += "</style></head><body>";
html += "<div class='header'>";
html += "<h2 onclick=\"window.location.href='/'\">ESR369</h2>";
html += "<form action='/search' method='GET' style='margin:0; width:100%;'>";
html += "<input type='text' name='q' value='" + query + "' required>";
html += "</form></div>";
html += "<div class='result-box'>";
html += "<div class='url'>Source: Wikipedia API </div>";
html += "<div class='title'>" + resultTitle + "</div>";
html += "<div class='desc'>" + resultText + "</div>";
html += "</div>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Captive Portal Redirect
void handleNotFound() {
server.sendHeader("Location", "/", true);
server.send(302, "text/plain", "");
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\nStarting ESP32 Search Engine...");
// Set mode to Both Station (Connect to Router) and AP (Host Network)
WiFi.mode(WIFI_AP_STA);
// 1. Connect to Internet (STA Mode)
Serial.print("Connecting to Backend WiFi: ");
Serial.println(sta_ssid);
WiFi.begin(sta_ssid, sta_pass);
// 2. Start Access Point (AP Mode)
Serial.print("Starting AP: ");
Serial.println(ap_ssid);
WiFi.softAP(ap_ssid);
Serial.print("AP IP Address: ");
Serial.println(WiFi.softAPIP());
// 3. Start Captive Portal (Redirect all DNS requests to ESP32 IP)
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
// 4. Setup Web Server Routes
server.on("/", handleRoot);
server.on("/search", handleSearch);
server.on("/generate_204", handleRoot); // Android Captive Portal
server.on("/hotspot-detect.html", handleRoot); // Apple Captive Portal
server.onNotFound(handleNotFound); // Catch-all redirect
server.begin();
Serial.println("ESR369 Server is UP & RUNNING!");
}
void loop() {
// Handle DNS requests for Captive Portal
dnsServer.processNextRequest();
// Handle HTTP client requests
server.handleClient();
}
Comments
Post a Comment