1 Star 9 Fork 1

隽恬 / ESP32-8266 配网

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 22.29 KB
一键复制 编辑 原始数据 按行查看 历史
隽恬 提交于 2022-03-23 01:02 . update README.md.

ESP32-8266 配网

Fork me on Gitee

web配网

web配网-强制门户配网,连接开放Ap,登陆:192.168.4.1,设置SSID,password,连接网络,关闭配网AP。长按GPIO0 3秒以上清楚配网信息,重新配网。 ​ 设备内做了个小web服务器通过网页交换SSID和PWD。这个方式比较友好,不依赖外部app或小程序,保密性更好,产品可用性更好。(苹果等个别手机不能打开配网页面可直接浏览器登陆192.168.4.1)。

操作方法:

  1. 连接开放Ap,
  2. 强制门户配网,
  3. 或登陆:192.168.4.1
  4. 设置SSID,password,
  5. 连接网络,
  6. 关闭配网AP。
  7. 长按GPIO0 3秒以上清除配网信息,
  8. 重新配网

web配网代码

#include <WiFi.h>
#include <DNSServer.h>
#include <WebServer.h>
#include <ESPmDNS.h>      //用于设备域名 MDNS.begin("esp32")
#include <esp_wifi.h>     //用于esp_wifi_restore() 删除保存的wifi信息




//************************************WEB配网***********************************************
const byte DNS_PORT = 53;                  //设置DNS端口号
const int webPort = 80;                    //设置Web端口号
const int resetPin = 0;                    //设置重置按键引脚,用于删除WiFi信息
const int LED = 2;                         //设置LED引脚
const char* AP_SSID  = "ESP32-4_1";    //设置AP热点名称
//const char* AP_PASS  = "";               //设置AP热点密码
const char* HOST_NAME = "MY_ESP32";       //设置设备名
String scanNetworksID = "";                //用于储存扫描到的WiFi ID
int connectTimeOut_s = 15;                 //WiFi连接超时时间,单位秒
IPAddress apIP(192, 168, 4, 1);            //设置AP的IP地址
String wifi_ssid = "";                     //暂时存储wifi账号密码
String wifi_pass = "";                     //暂时存储wifi账号密码

//定义根目录首页网页HTML源代码
#define ROOT_HTML  "
<!DOCTYPE html><html><head><title>WIFI Config by lwang</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=\"POST\" action=\"configwifi\">
<label class=\"input\">
  <span>WiFi SSID</span>
    <input type=\"text\" name=\"ssid\" value=\"\">
</label>
<label class=\"input\">
  <span>WiFi PASS</span>
    <input type=\"text\"  name=\"pass\">
</label>
    <input class=\"btn\" type=\"submit\" name=\"submit\" value=\"Submie\"> 
<p><span> Nearby wifi:</P></form>"

//定义成功页面HTML源代码
#define SUCCESS_HTML  "
<html>
<body>
  <font size=\"10\">successd,wifi connecting...
    <br />Please close this page manually.
  </font>
</body>
</html>"

DNSServer dnsServer;            //创建dnsServer实例
WebServer server(webPort);      //开启web服务, 创建TCP SERVER,参数: 端口号,最大连接数

//初始化AP模式
void initSoftAP() {
  WiFi.mode(WIFI_AP);     //配置为AP模式
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));   //设置AP热点IP和子网掩码
  if (WiFi.softAP(AP_SSID)) { //开启AP热点,如需要密码则添加第二个参数
    //打印相关信息
    Serial.println("ESP-32S SoftAP is right.");
    Serial.print("Soft-AP IP address = ");
    Serial.println(WiFi.softAPIP());
    Serial.println(String("MAC address = ")  + WiFi.softAPmacAddress().c_str());
  } else { //开启热点失败
    Serial.println("WiFiAP Failed");
    delay(1000);
    Serial.println("restart now...");
    ESP.restart();  //重启复位esp32
  }
}

//初始化DNS服务器
void initDNS() {
  //判断将所有地址映射到esp32的ip上是否成功
  if (dnsServer.start(DNS_PORT, "*", apIP)) {
    Serial.println("start dnsserver success.");
  } else {
    Serial.println("start dnsserver failed.");
  }
}

//初始化WebServer
void initWebServer() {
  //给设备设定域名esp32,完整的域名是esp32.local
  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }
  //必须添加第二个参数HTTP_GET,以下面这种格式去写,否则无法强制门户
  server.on("/", HTTP_GET, handleRoot);                      //  当浏览器请求服务器根目录(网站首页)时调用自定义函数handleRoot处理,设置主页回调函数,必须添加第二个参数HTTP_GET,否则无法强制门户
  server.on("/configwifi", HTTP_POST, handleConfigWifi);     //  当浏览器请求服务器/configwifi(表单字段)目录时调用自定义函数handleConfigWifi处理
  server.onNotFound(handleNotFound);                         //当浏览器请求的网络资源无法在服务器找到时调用自定义函数handleNotFound处理

  server.begin();                                           //启动TCP SERVER

  Serial.println("WebServer started!");
}

//扫描WiFi
bool scanWiFi() {
  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";
    return false;
  } 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);
    }
    return true;
  }
}

void connectToWiFi(int timeOut_s) {
  Serial.println("进入connectToWiFi()函数");
  //设置为STA模式并连接WIFI
  WiFi.mode(WIFI_STA);
  WiFi.setAutoConnect(true);//设置自动连接
  //用字符串成员函数c_str()生成一个const char*指针,指向以空字符终止的数组,即获取该字符串的指针。
  if (wifi_ssid != "") {
    Serial.println("用web配置信息连接.");

    WiFi.begin(wifi_ssid.c_str(), wifi_pass.c_str());
    wifi_ssid = "";
    wifi_pass = "";
  } else {
    Serial.println("用nvs保存的信息连接.");
    WiFi.begin();//连接上一次连接成功的wifi
  }

  int Connect_time = 0; //用于连接计时,如果长时间连接不成功,复位设备
  while (WiFi.status() != WL_CONNECTED) {  //等待WIFI连接成功
    Serial.print(".");
    digitalWrite(LED, !digitalRead(LED));
    delay(500);
    Connect_time ++;
    if (Connect_time > 2 * timeOut_s) { //长时间连接不上,重新进入配网页面
      digitalWrite(LED, LOW);
      Serial.println("");
      Serial.println("WIFI autoconnect fail, start AP for webconfig now...");
      wifiConfig();   //转到网页端手动配置wifi
      return;         //跳出 防止无限初始化

    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WIFI connect 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());
    Serial.print("WIFI status is:");

    Serial.print(WiFi.status());
    digitalWrite(LED, HIGH);
    server.stop();
  }
}

//用于配置WiFi
void wifiConfig() {
  initSoftAP();
  initDNS();
  initWebServer();
  scanWiFi();
}

//处理网站根目录“/”(首页)的访问请求,将显示配置wifi的HTML页面
void handleRoot() {
  if (server.hasArg("selectSSID")) {
    server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
  } else {
    server.send(200, "text/html", ROOT_HTML + scanNetworksID + "</body></html>");
  }
}
//提交数据后,返回给客户端信息函数
void handleConfigWifi() {
  //返回http状态

  if (server.hasArg("ssid")) {//判断是否有账号参数
    Serial.print("got ssid:");
    wifi_ssid = server.arg("ssid");      //获取html表单输入框name名为"ssid"的内容

    Serial.println(wifi_ssid);
  } else { //没有参数
    Serial.println("error, not found ssid");
    server.send(200, "text/html", "<meta charset='UTF-8'>error, not found ssid");//返回错误页面
    return;
  }
  //密码与账号同理
  if (server.hasArg("pass")) {
    Serial.print("got password:");
    wifi_pass = server.arg("pass");       //获取html表单输入框name名为"pwd"的内容
    //strcpy(sta_pass, server.arg("pass").c_str());
    Serial.println(wifi_pass);
  } else {
    Serial.println("error, not found password");
    server.send(200, "text/html", "<meta charset='UTF-8'>error, not found password");
    return;
  }
  server.send(200, "text/html", "<meta charset='UTF-8'>SSID:" + wifi_ssid + "<br />password:" + wifi_pass + "<br />已取得WiFi信息,正在尝试连接,请手动关闭此页面。"); //返回保存成功页面
  delay(2000);
  WiFi.softAPdisconnect(true);     //参数设置为true,设备将直接关闭接入点模式,即关闭设备所建立的WiFi网络。
  server.close();                  //关闭web服务
  WiFi.softAPdisconnect();         //在不输入参数的情况下调用该函数,将关闭接入点模式,并将当前配置的AP热点网络名和密码设置为空值.
  Serial.println("WiFi Connect SSID:" + wifi_ssid + "  PASS:" + wifi_pass);
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("开始调用连接函数connectToWiFi()..");
    connectToWiFi(connectTimeOut_s);//进入配网阶段
  } else {
    Serial.println("提交的配置信息自动连接成功..");
  }
}

// 设置处理404情况的函数'handleNotFound'
void handleNotFound() {           // 当浏览器请求的网络资源无法在服务器找到时通过此自定义函数处理
  handleRoot();                 //访问不存在目录则返回配置页面
  //   server.send(404, "text/plain", "404: Not found");
}

//LED闪烁,led为脚号,n为次数,t为时间间隔ms
void blinkLED(int led, int n, int t) {
  for (int i = 0; i < 2 * n; i++) {
    digitalWrite(led, !digitalRead(led));
    delay(t);
  }
}

//删除保存的wifi信息,并使LED闪烁5次
void restoreWiFi() {
  delay(500);
  esp_wifi_restore();  //删除保存的wifi信息
  Serial.println("连接信息已清空,准备重启设备..");
  delay(10);
  blinkLED(LED, 5, 500); //LED闪烁5次
  digitalWrite(LED, LOW);
}

void checkConnect(bool reConnect) {
  if (WiFi.status() != WL_CONNECTED) {

    if (digitalRead(LED) != LOW) {
      digitalWrite(LED, LOW);
    }
    if (reConnect == true && WiFi.getMode() != WIFI_AP && WiFi.getMode() != WIFI_AP_STA ) {
      Serial.println("WIFI未连接.");
      Serial.println("WiFi Mode:");
      Serial.println(WiFi.getMode());
      Serial.println("正在连接WiFi...");
      connectToWiFi(connectTimeOut_s);
    }
  } else if (digitalRead(LED) != HIGH) {
    digitalWrite(LED, HIGH);
  }
}
//************************************WEB配网***********************************************



void setup() {
  //************************************WEB配网***********************************************
  pinMode(LED, OUTPUT);                 //配置LED口为输出口
  digitalWrite(LED, LOW);               //初始灯灭
  pinMode(resetPin, INPUT_PULLUP);      //按键上拉输入模式(默认高电平输入,按下时下拉接到低电平)
  Serial.begin(115200);
  WiFi.hostname(HOST_NAME);             //设置设备名
  connectToWiFi(connectTimeOut_s);
  //************************************AP配网***********************************************



}

void loop() {
  //************************************WEB配网***********************************************
  //长按5秒(P0)清除网络配置信息
  if (!digitalRead(resetPin)) {
    delay(5000);
    if (!digitalRead(resetPin)) {
      Serial.println("\n按键已长按5秒,正在清空网络连保存接信息.");
      restoreWiFi();    //删除保存的wifi信息
      ESP.restart();    //重启复位esp32
      Serial.println("已重启设备.");
    }
  }

  dnsServer.processNextRequest();   //检查客户端DNS请求
  server.handleClient();            //检查客户端(浏览器)http请求
  checkConnect(true);               //检测网络连接状态,参数true表示如果断开重新连接

  delay(30);
  //************************************WEB配网***********************************************





}

smartconfig配网

手机通过软件发送UDP广播包配网,需要小程序或乐鑫配网app配合使用,代码简单。

  1. 扫二维码或打开配网app
  2. 填写SSID和密码
  3. 选择smartconfig配网方式,
  4. 开始配网,打开串口工具可以看到配网进度和结果(不在pc边就等等,打开应用查看是否联网)。 输入图片说明

smartconfig配网代码

#ifdef ESP8266
  #include <ESP8266WiFi.h>       // Built-in
#else
  #include <WiFi.h>              // Built-in
#endif

void SmartConfig()
{
   WiFi.mode(WIFI_STA);
   Serial.println("\r\n wait for smartconfig....");
   WiFi.beginSmartConfig();
   while(1)
   {
    Serial.print(".");
    delay(500);
    if ( WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n",WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n",WiFi.psk().c_str());
      break;      
    }
   }  
}

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(",PWS:%s\r\n",WiFi.psk().c_str());
          Serial.print("localIP:");
          Serial.println(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);
  delay(100);
  if (!AutoConfig())
  {
    SmartConfig();
  }
  //下面放你的setup代码 put your setup code here, to run once:

  
}

void loop() {
  // 放你的mani代码 重复执行put your main code here, to run repeatedly:

}

BluFi蓝牙配网

​ 概览 BluFi 是一款基于蓝牙通道的 Wi-Fi 网络配置功能,适用于 ESP32。它通过安全协议将 Wi-Fi 配置和证书传输到 ESP32,然后 ESP32 可基于这些信息连接到 AP 或建立 SoftAP。

用户可按需自定义用于对称加密、非对称加密和校验的算法。这里我们采用 DH 算法进行密钥协商、128-AES 算法用于数据加密、CRC16 算法用于校验和验证。

BluFi 流程 BluFi 配网功能包含配置 SoftAP 和 Station 两部分。

下面以配置 Station 为例说明配置步骤。 BluFi 配网的配置 Station 包含广播、连接、服务发现、协商共享密钥、传输数据、回传连接状态等步骤。

BluFi蓝牙配网代码

/********************** BluetoothWifi ***************************/
#include <WiFi.h>
#include <Preferences.h>
#include "BluetoothSerial.h"
/********************** 放置你的include代码 ***************************/



/********************** BluetoothWifi ***************************/
String ssids_array[50];
String network_string;
String connected_string;

const char* pref_ssid = "";
const char* pref_pass = "";
String client_wifi_ssid;
String client_wifi_password;

const char* bluetooth_name = "ESP32 BLE";

long start_wifi_millis;
long wifi_timeout = 10000;
bool bluetooth_disconnect = false;

enum wifi_setup_stages { NONE, SCAN_START, SCAN_COMPLETE, SSID_ENTERED, WAIT_PASS, PASS_ENTERED, WAIT_CONNECT, LOGIN_FAILED };
enum wifi_setup_stages wifi_stage = NONE;

BluetoothSerial SerialBT;
Preferences preferences;
/********************** 放置你的变量定义 ***************************/



/********************** BluetoothWifi ***************************/
bool init_wifi()
{
  String temp_pref_ssid = preferences.getString("pref_ssid");
  String temp_pref_pass = preferences.getString("pref_pass");
  pref_ssid = temp_pref_ssid.c_str();
  pref_pass = temp_pref_pass.c_str();

  Serial.println(pref_ssid);
  Serial.println(pref_pass);

  WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);

    WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(pref_ssid);
  WiFi.begin(pref_ssid, pref_pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  
    if (millis() - start_wifi_millis > wifi_timeout) {
      WiFi.disconnect(true, true);
      return false;
    }
  }
      
       Serial.println();
  Serial.print("ESP32-CAM IP Address: ");
  Serial.println(WiFi.localIP());
  
  return true;
}

void scan_wifi_networks()
{
  WiFi.mode(WIFI_STA);
  // WiFi.scanNetworks will return the number of networks found
  int n =  WiFi.scanNetworks();
  if (n == 0) {
    SerialBT.println("no networks found");
  } else {
    SerialBT.println();
    SerialBT.print(n);
    SerialBT.println(" networks found");
    delay(1000);
    for (int i = 0; i < n; ++i) {
      ssids_array[i + 1] = WiFi.SSID(i);
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.println(ssids_array[i + 1]);
      network_string = i + 1;
      network_string = network_string + ": " + WiFi.SSID(i) + " (Strength:" + WiFi.RSSI(i) + ")";
      SerialBT.println(network_string);
    }
    wifi_stage = SCAN_COMPLETE;
  }
}

void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
  
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    wifi_stage = SCAN_START;
  }

  if (event == ESP_SPP_DATA_IND_EVT && wifi_stage == SCAN_COMPLETE) { // data from phone is SSID
    int client_wifi_ssid_id = SerialBT.readString().toInt();
    client_wifi_ssid = ssids_array[client_wifi_ssid_id];
    wifi_stage = SSID_ENTERED;
  }

  if (event == ESP_SPP_DATA_IND_EVT && wifi_stage == WAIT_PASS) { // data from phone is password
    client_wifi_password = SerialBT.readString();
    client_wifi_password.trim();
    wifi_stage = PASS_ENTERED;
  }

}

void callback_show_ip(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
  if (event == ESP_SPP_SRV_OPEN_EVT) {
    SerialBT.print("ESP32 IP: ");
    SerialBT.println(WiFi.localIP());
    bluetooth_disconnect = true;
  }
}


void disconnect_bluetooth()
{
  delay(1000);
  Serial.println("BT stopping");
  SerialBT.println("Bluetooth disconnecting...");
  delay(1000);
  SerialBT.flush();
  SerialBT.disconnect();
  SerialBT.end();
  Serial.println("BT stopped");
  delay(1000);
  bluetooth_disconnect = false;
}
/********************** 放置你的子函数 ***************************/




void setup()
{
/********************** BluetoothWifi ***************************/
  Serial.begin(115200);
  Serial.println("Booting...");

  preferences.begin("wifi_access", false);

  if (!init_wifi()) { // Connect to Wi-Fi fails
    SerialBT.register_callback(callback);
  } else {
    SerialBT.register_callback(callback_show_ip);
  }

  SerialBT.begin(bluetooth_name);
/********************** 放置你的setup代码,执行一次 ***************************/
 Serial.println("Test just once...");

}

void loop()
{
/********************** BluetoothWifi ***************************/
  if (bluetooth_disconnect)
  {
    disconnect_bluetooth();
  }

  switch (wifi_stage)
  {
    case SCAN_START:
      SerialBT.println("Scanning Wi-Fi networks");
      Serial.println("Scanning Wi-Fi networks");
      scan_wifi_networks();
      SerialBT.println("Please enter the number for your Wi-Fi");
      wifi_stage = SCAN_COMPLETE;
      break;

    case SSID_ENTERED:
      SerialBT.println("Please enter your Wi-Fi password");
      Serial.println("Please enter your Wi-Fi password");
      wifi_stage = WAIT_PASS;
      break;

    case PASS_ENTERED:
      SerialBT.println("Please wait for Wi-Fi connection...");
      Serial.println("Please wait for Wi_Fi connection...");
      wifi_stage = WAIT_CONNECT;
      preferences.putString("pref_ssid", client_wifi_ssid);
      preferences.putString("pref_pass", client_wifi_password);
      if (init_wifi()) { // Connected to WiFi
        connected_string = "ESP32 IP: ";
        connected_string = connected_string + WiFi.localIP().toString();
        SerialBT.println(connected_string);
        Serial.println(connected_string);
        bluetooth_disconnect = true;
      } else { // try again
        wifi_stage = LOGIN_FAILED;
      }
      break;

    case LOGIN_FAILED:
      SerialBT.println("Wi-Fi connection failed");
      Serial.println("Wi-Fi connection failed");
      delay(2000);
      wifi_stage = SCAN_START;
      break;
  }
/********************** 放置你的loop代码,重复执行 ***************************/

 Serial.println("Test repeat...");
 delay(5000);

  
}

特技

  1. 使用 Readme_XXX.md 来支持不同的语言,例如 Readme_en.md, Readme_zh.md
  2. Gitee 官方博客 blog.gitee.com
  3. 你可以 https://gitee.com/explore 这个地址来了解 Gitee 上的优秀开源项目
  4. GVP 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
  5. Gitee 官方提供的使用手册 https://gitee.com/help
  6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 https://gitee.com/gitee-stars/
C++
1
https://gitee.com/jun-tian/esp32-web-distribution-network.git
git@gitee.com:jun-tian/esp32-web-distribution-network.git
jun-tian
esp32-web-distribution-network
ESP32-8266 配网
master

搜索帮助