ESP32.jpg

简述

在 ESP32 的官方程序中,都是将 WIFI 信息写死在代码中,在实际应用的网络环境中,网络环境可能会变化,这就不方便我们的开发与使用。理想的状态是可以灵活配置 WIFI 信息,再进一步就可以考虑自动保存删除 WIFI 信息等功能。

思路

ESP32 有 AP 模式和 STA 模式,所以我们可以启动 ESP32 后使用 AP 模式,生成一个 WEB 页面供我们来配置 WIFI 信息,配置成功之后就自动切换到 STA 模式连接 WIFI,执行后续功能。

整体流程为:

启动 -----> AP模式 ------> 移动设备连接AP热点登录web页面配置WIFI -------> STA 模式,连接WIFI -----> 结束

代码

#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <esp_wifi.h>
​
const char* AP_SSID  = "ESP32_Config"; //热点名称
// const char* AP_PASSWD = "esp32666"; //热点密码(可以不开启)
String wifi_ssid = "";
String wifi_pass = "";
String scanNetworksID = "";//用于储存扫描到的WiFi
​
#define ROOT_HTML  "<!DOCTYPE html><html><head><title>ESP32 WIFI Config</title><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><style type=\"text/css\">.input{display: block; margin-top: 10px;}.input span{width: 100px; float: left; float: left; height: 36px; line-height: 36px;}.input input{height: 30px;width: 200px;}.btn{width: 120px; height: 35px; background-color: #000000; border:0px; color:#ffffff; margin-top:15px; margin-left:100px;}</style><body><form method=\"GET\" action=\"connect\"><label class=\"input\"><span>WiFi SSID</span><input type=\"text\" name=\"ssid\"></label><label class=\"input\"><span>WiFi PASS</span><input type=\"text\"  name=\"pass\"></label><input class=\"btn\" type=\"submit\" name=\"submit\" value=\"Submie\"> <div class=\"wifi-container\"><p><span style=\"background-color: yellow;\">Nearby wifi:</span></p></div></form>"
WebServer server(80);
​
#define RESET_PIN 13  //用于删除WiFi信息
​
//用于配置WiFi
void wifi_Config()
{
  Serial.println("scan start");
  // 扫描附近WiFi
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
    scanNetworksID = "no networks found";
  } else {
    Serial.print(n);
    Serial.println("networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      scanNetworksID += "<P>" + WiFi.SSID(i) + "</P>";
      delay(10);
    }
  }
  Serial.println("");
​
  WiFi.mode(WIFI_AP);//配置为AP模式
  boolean result = WiFi.softAP(AP_SSID, ""); //开启WIFI热点
  // boolean result = WiFi.softAP(AP_SSID, AP_PASSWD); //开启WIFI热点(带密码)
​
  if (result)
  {
    IPAddress myIP = WiFi.softAPIP();
    //打印相关信息
    Serial.println("");
    Serial.print("Soft-AP IP address = ");
    Serial.println(myIP);
    Serial.println(String("MAC address = ")  + WiFi.softAPmacAddress().c_str());
    Serial.println("waiting ...");
  } else {  //开启热点失败
    Serial.println("WiFiAP Failed");
    delay(3000);
    ESP.restart();  //复位esp32
  }
​
  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }
​
  //首页
  server.on("/", []() {
    server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
  });
​
  //连接
  server.on("/connect", []() {
​
    server.send(200, "text/html", "<html><body><font size=\"10\">successd,wifi connecting...<br />Please close this page manually.</font></body></html>");
​
    WiFi.softAPdisconnect(true);
    //获取输入的WIFI账户和密码
    wifi_ssid = server.arg("ssid");
    wifi_pass = server.arg("pass");
    server.close();
    WiFi.softAPdisconnect();
    Serial.println("WiFi Connect SSID:" + wifi_ssid + "  PASS:" + wifi_pass);
​
    //设置为STA模式并连接WIFI
    WiFi.mode(WIFI_STA);
    WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str());
    uint8_t Connect_time = 0; //用于连接计时,如果长时间连接不成功,复位设备
    while (WiFi.status() != WL_CONNECTED) {  //等待WIFI连接成功
      delay(500);
      Serial.print(".");
      Connect_time ++;
      if (Connect_time > 80) {  //长时间连接不上,复位设备
        Serial.println("Connection timeout, check input is correct or try again later!");
        delay(3000);
        ESP.restart();
      }
    }
    Serial.println("");
    Serial.println("WIFI Config Success");
    Serial.printf("SSID:%s", WiFi.SSID().c_str());
    Serial.print("  LocalIP:");
    Serial.print(WiFi.localIP());
    Serial.println("");
​
  });
  server.begin();
}
​
//用于上电自动连接WiFi
bool AutoConfig()
{
  WiFi.begin();
  for (int i = 0; i < 20; i++)
  {
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED)
    {
      Serial.println("WIFI SmartConfig Success");
      Serial.printf("SSID:%s", WiFi.SSID().c_str());
      Serial.printf(", PSW:%s\r\n", WiFi.psk().c_str());
      Serial.print("LocalIP:");
      Serial.print(WiFi.localIP());
      Serial.print(" ,GateIP:");
      Serial.println(WiFi.gatewayIP());
      return true;
    }
    else
    {
      Serial.print("WIFI AutoConfig Waiting......");
      Serial.println(wstatus);
      delay(1000);
    }
  }
  Serial.println("WIFI AutoConfig Faild!" );
  return false;
}
​
void setup() {
​
  Serial.begin(115200);
  pinMode(RESET_PIN, INPUT_PULLUP);
​
  // 连接WiFi
  if (!AutoConfig())
  {
    wifi_Config();
  }
​
  //用于删除已存WiFi
  if (digitalRead(RESET_PIN) == LOW) {
    delay(1000);
    esp_wifi_restore();
    delay(10);
    ESP.restart();  //复位esp32
  }
​
  /*****************************/
  /*********用户配置代码*********/
  /*****************************/
  pinMode(2, OUTPUT);   // 板载LED 引脚
  /*****************************/
  /*****************************/
}
​
void loop() {
  server.handleClient();
  while (WiFi.status() == WL_CONNECTED) {
      //WIFI已连接, 此处可以编写WIFI连接成功之后的Loop操作
      /*****************************/
      /*********用户Loop代码*********/
      /*****************************/
      digitalWrite(2,HIGH); // 灯亮
      delay(500);
      digitalWrite(2,LOW); // 灯灭
      delay(500);
      /*****************************/
      /*****************************/
  }
}

上述代码仅是 demo,在 WIFI 连接成功后实现闪烁板载 LED,具体用户功能可自行添加。

效果

实现的功能

  • Web 配置 WIFI 信息

  • 默认拉高 GPIO13 ,接地上电即可删除 WIFI 信息

  • 自动保存 WIFI 信息,方便重连

客户端连接上esp32的热点后,打开 192.168.4.1 网址就可以访问 WIFI 配置页面了。

效果图

以我的ESP32开发板为例:

以下是我的引脚图:

GPIO_map.jpg

下面是连接到 Web 页面的效果:

config_web.png

要想清除WIFI信息,短接 GPIO13 和 GND 后重启即可。